mailkick 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7342fb3956753b14f1345a70153ac76cc6cc73290a7b4c1d9e3f9a1b29e6a216
4
- data.tar.gz: 06a13e7037c2ab1ffcab78f93f7a99272aa00b59f3388878ad10498d7ed73e70
3
+ metadata.gz: 5a3e1a782d63a1ad223871a87aab2875c73c1a7860f614801184d005113d4d82
4
+ data.tar.gz: 802fdb1f89e3ca6c25761bb61fd085b1936336ea5fd6bc6a020a1b79a21859c0
5
5
  SHA512:
6
- metadata.gz: 2d0a3d927fee65871caf6b37d79e83663e45c382396e941e03651ec36de13e19680107f9582e4e9010f65454361d32e16b77787d8e0657857029ff05b3e2e510
7
- data.tar.gz: 72698be727b60185179d2004af23531cf3812fabf6e68a8ad0d4da4b0119804bc3591dd60aa1f7a5c92b1d3d0c896f5329572a6e331985724f00c8778abb6623
6
+ metadata.gz: e93ee8b3bcf05fa1536141e2f9ef639e30efd236eb9d280bb88bc7e234f6a6aa9a246eb91bd6aee188c74226e11cf0cdcb67e636ffafeb76f525f89096ec5eda
7
+ data.tar.gz: 23441f577b0f294a46f47e61cc66c994a319d1e3d89ff310bd26d997c5b6bdbd2270318fda74de96e588f7da58691c63d3c188853be382a41a3608803034435d
@@ -1,73 +1,98 @@
1
- ## 0.3.0
1
+ ## 0.4.3 (2020-11-01)
2
+
3
+ - Added support for AWS SES
4
+
5
+ ## 0.4.2 (2020-04-06)
6
+
7
+ - Added support for official SendGrid gem
8
+ - Fixed deprecation warning
9
+
10
+ ## 0.4.1 (2019-10-27)
11
+
12
+ - Added Postmark support
13
+
14
+ ## 0.4.0 (2019-07-15)
15
+
16
+ - Fixed error with model methods and `email_key` option
17
+ - Fixed bug with `opted_out` scope
18
+ - Dropped support for Action Mailer 4.2
19
+
20
+ ## 0.3.1 (2018-04-21)
21
+
22
+ - Fixed `Secret should not be nil` error in Rails 5.2
23
+ - Gracefully handle missing email
24
+ - Added `user` option to `mailkick_unsubscribe_url`
25
+
26
+ ## 0.3.0 (2018-04-20)
2
27
 
3
28
  - Improved performance
4
29
  - Fixed `Subscription not found` for Rails 5.2
5
30
  - Use `references` in migration
6
31
  - Use `smtp_settings[:domain]` for Mailgun
7
- - Dropped support for ActionMailer < 4.2
32
+ - Dropped support for Action Mailer < 4.2
8
33
 
9
- ## 0.2.1
34
+ ## 0.2.1 (2017-10-30)
10
35
 
11
36
  - Fixed errors with Rails 5+
12
37
  - Fixed errors with the latest version of Gibbon
13
38
 
14
- ## 0.2.0
39
+ ## 0.2.0 (2017-05-01)
15
40
 
16
41
  - Added support for Rails 5.1
17
42
 
18
- ## 0.1.6
43
+ ## 0.1.6 (2017-01-10)
19
44
 
20
45
  - Fixed error with frozen strings
21
46
 
22
- ## 0.1.5
47
+ ## 0.1.5 (2016-12-06)
23
48
 
24
49
  - Use `safely`
25
50
  - Only discover services if not manually set
26
51
  - Added `mount` option
27
52
 
28
- ## 0.1.4
53
+ ## 0.1.4 (2016-02-20)
29
54
 
30
55
  - Use `Module#prepend` instead of `alias_method_chain`
31
56
 
32
- ## 0.1.3
57
+ ## 0.1.3 (2015-06-29)
33
58
 
34
59
  - Fixed issue with double escaping tokens
35
60
 
36
- ## 0.1.2
61
+ ## 0.1.2 (2015-06-07)
37
62
 
38
63
  - Added support for Mailgun
39
64
 
40
- ## 0.1.1
65
+ ## 0.1.1 (2015-01-31)
41
66
 
42
67
  - Fixed tokens with `+` in them
43
68
 
44
- ## 0.1.0
69
+ ## 0.1.0 (2014-08-31)
45
70
 
46
71
  - Fixed secret token for Rails 4.1
47
72
 
48
- ## 0.0.6
73
+ ## 0.0.6 (2014-05-09)
49
74
 
50
75
  - Rails 3 fix
51
76
 
52
- ## 0.0.5
77
+ ## 0.0.5 (2014-05-05)
53
78
 
54
79
  - Fixed bug with subscriptions page
55
80
 
56
- ## 0.0.4
81
+ ## 0.0.4 (2014-05-05)
57
82
 
58
83
  - Added `email_key` option to `mailkick_user`
59
84
 
60
- ## 0.0.3
85
+ ## 0.0.3 (2014-05-04)
61
86
 
62
87
  - Added support for multiple lists
63
88
  - Changed `mailkick_user` method names - sorry early adopters :(
64
89
 
65
- ## 0.0.2
90
+ ## 0.0.2 (2014-05-04)
66
91
 
67
92
  - Added Mailchimp service
68
93
  - Fixed Mandrill service
69
94
  - Added `uniq` to `subscribed` scope
70
95
 
71
- ## 0.0.1
96
+ ## 0.0.1 (2014-05-04)
72
97
 
73
98
  - First release
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Andrew Kane
1
+ Copyright (c) 2014-2019 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Mailkick
2
2
 
3
- Email subscriptions made easy
3
+ Email unsubscribes 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
@@ -89,43 +89,76 @@ Fetch bounces, spam reports, and unsubscribes from your email service.
89
89
  Mailkick.fetch_opt_outs
90
90
  ```
91
91
 
92
- #### Sendgrid
92
+ The following services are supported:
93
93
 
94
- Add the gem
94
+ - [AWS SES](#aws-ses)
95
+ - [Mailchimp](#mailchimp)
96
+ - [Mailgun](#mailgun)
97
+ - [Mandrill](#mandrill)
98
+ - [Postmark](#postmark)
99
+ - [SendGrid](#sendgrid)
95
100
 
96
- ```ruby
97
- gem 'sendgrid_toolkit'
98
- ```
101
+ Will gladly accept pull requests for others.
99
102
 
100
- Be sure `ENV["SENDGRID_USERNAME"]` and `ENV["SENDGRID_PASSWORD"]` are set.
103
+ #### AWS SES
101
104
 
102
- #### Mandrill
105
+ Add the gem
103
106
 
104
107
  ```ruby
105
- gem 'mandrill-api'
108
+ gem 'aws-sdk-sesv2'
106
109
  ```
107
110
 
108
- Be sure `ENV["MANDRILL_APIKEY"]` is set.
111
+ And [configure your AWS credentials](https://github.com/aws/aws-sdk-ruby#configuration). Requires `ses:ListSuppressedDestinations` permission.
109
112
 
110
113
  #### Mailchimp
111
114
 
115
+ Add the gem
116
+
112
117
  ```ruby
113
118
  gem 'gibbon', '>= 2'
114
119
  ```
115
120
 
116
- Be sure `ENV["MAILCHIMP_API_KEY"]` and `ENV["MAILCHIMP_LIST_ID"]` are set.
121
+ And set `ENV["MAILCHIMP_API_KEY"]` and `ENV["MAILCHIMP_LIST_ID"]`.
117
122
 
118
123
  #### Mailgun
119
124
 
125
+ Add the gem
126
+
120
127
  ```ruby
121
128
  gem 'mailgun-ruby'
122
129
  ```
123
130
 
124
- Be sure `ENV["MAILGUN_API_KEY"]` is set.
131
+ And set `ENV["MAILGUN_API_KEY"]`.
125
132
 
126
- #### Other
133
+ #### Mandrill
134
+
135
+ Add the gem
136
+
137
+ ```ruby
138
+ gem 'mandrill-api'
139
+ ```
140
+
141
+ And set `ENV["MANDRILL_APIKEY"]`.
127
142
 
128
- Will gladly accept pull requests.
143
+ #### Postmark
144
+
145
+ Add the gem
146
+
147
+ ```ruby
148
+ gem 'postmark'
149
+ ```
150
+
151
+ And set `ENV["POSTMARK_API_KEY"]`.
152
+
153
+ #### SendGrid
154
+
155
+ Add the gem
156
+
157
+ ```ruby
158
+ gem 'sendgrid-ruby'
159
+ ```
160
+
161
+ And set `ENV["SENDGRID_API_KEY"]`. The API key requires only the `Suppressions` permission.
129
162
 
130
163
  ### Advanced
131
164
 
@@ -133,8 +166,8 @@ For more control over services, set them by hand.
133
166
 
134
167
  ```ruby
135
168
  Mailkick.services = [
136
- Mailkick::Service::Sendgrid.new(api_key: "API_KEY"),
137
- Mailkick::Service::Mandrill.new(api_key: "API_KEY")
169
+ Mailkick::Service::SendGridV2.new(api_key: "API_KEY"),
170
+ Mailkick::Service::Mailchimp.new(api_key: "API_KEY", list_id: "LIST_ID")
138
171
  ]
139
172
  ```
140
173
 
@@ -203,6 +236,12 @@ Resubscribe
203
236
  user.opt_in
204
237
  ```
205
238
 
239
+ Access the opt-out model directly
240
+
241
+ ```ruby
242
+ Mailkick::OptOut.all
243
+ ```
244
+
206
245
  ## History
207
246
 
208
247
  View the [changelog](https://github.com/ankane/mailkick/blob/master/CHANGELOG.md)
@@ -215,3 +254,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
215
254
  - Fix bugs and [submit pull requests](https://github.com/ankane/mailkick/pulls)
216
255
  - Write, clarify, or fix documentation
217
256
  - Suggest or add new features
257
+
258
+ To get started with development and testing:
259
+
260
+ ```sh
261
+ git clone https://github.com/ankane/mailkick.git
262
+ cd mailkick
263
+ bundle install
264
+ bundle exec rake test
265
+ ```
@@ -31,11 +31,7 @@ module Mailkick
31
31
  list: @list
32
32
  }
33
33
  rescue ActiveSupport::MessageVerifier::InvalidSignature
34
- if Rails::VERSION::MAJOR >= 5
35
- render plain: "Subscription not found", status: :bad_request
36
- else
37
- render text: "Subscription not found", status: :bad_request
38
- end
34
+ render plain: "Subscription not found", status: :bad_request
39
35
  end
40
36
 
41
37
  def opted_out?
@@ -2,6 +2,6 @@ module Mailkick
2
2
  class OptOut < ActiveRecord::Base
3
3
  self.table_name = "mailkick_opt_outs"
4
4
 
5
- belongs_to :user, ActiveRecord::VERSION::MAJOR >= 5 ? {polymorphic: true, optional: true} : {polymorphic: true}
5
+ belongs_to :user, polymorphic: true, optional: true
6
6
  end
7
7
  end
@@ -1,34 +1,17 @@
1
- # taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
2
- require "rails/generators"
3
- require "rails/generators/migration"
4
- require "active_record"
5
1
  require "rails/generators/active_record"
6
2
 
7
3
  module Mailkick
8
4
  module Generators
9
5
  class InstallGenerator < Rails::Generators::Base
10
- include Rails::Generators::Migration
11
-
12
- source_root File.expand_path("../templates", __FILE__)
13
-
14
- # Implement the required interface for Rails::Generators::Migration.
15
- def self.next_migration_number(dirname) #:nodoc:
16
- next_migration_number = current_migration_number(dirname) + 1
17
- if ActiveRecord::Base.timestamped_migrations
18
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
19
- else
20
- "%.3d" % next_migration_number
21
- end
22
- end
6
+ include ActiveRecord::Generators::Migration
7
+ source_root File.join(__dir__, "templates")
23
8
 
24
9
  def copy_migration
25
10
  migration_template "install.rb", "db/migrate/install_mailkick.rb", migration_version: migration_version
26
11
  end
27
12
 
28
13
  def migration_version
29
- if ActiveRecord::VERSION::MAJOR >= 5
30
- "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
31
- end
14
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
32
15
  end
33
16
  end
34
17
  end
@@ -1,15 +1,25 @@
1
- require "set"
1
+ # dependencies
2
2
  require "active_support"
3
3
 
4
- require "mailkick/engine" if defined?(Rails)
4
+ # stdlib
5
+ require "set"
6
+
7
+ # modules
5
8
  require "mailkick/model"
6
9
  require "mailkick/service"
10
+ require "mailkick/service/aws_ses"
7
11
  require "mailkick/service/mailchimp"
8
12
  require "mailkick/service/mailgun"
9
13
  require "mailkick/service/mandrill"
10
14
  require "mailkick/service/sendgrid"
15
+ require "mailkick/service/sendgrid_v2"
16
+ require "mailkick/service/postmark"
17
+ require "mailkick/url_helper"
11
18
  require "mailkick/version"
12
19
 
20
+ # integrations
21
+ require "mailkick/engine" if defined?(Rails)
22
+
13
23
  module Mailkick
14
24
  mattr_accessor :services, :user_method, :secret_token, :mount
15
25
  self.services = []
@@ -56,17 +66,16 @@ module Mailkick
56
66
  def self.opt_outs(options = {})
57
67
  relation = Mailkick::OptOut.where(active: true)
58
68
 
59
- parts = []
60
- binds = []
69
+ contact_relation = Mailkick::OptOut.none
61
70
  if (email = options[:email])
62
- parts << "email = ?"
63
- binds << email
71
+ contact_relation = contact_relation.or(Mailkick::OptOut.where(email: email))
64
72
  end
65
73
  if (user = options[:user])
66
- parts << "(user_id = ? and user_type = ?)"
67
- binds.concat [user.id, user.class.name]
74
+ contact_relation = contact_relation.or(
75
+ Mailkick::OptOut.where("user_id = ? AND user_type = ?", user.id, user.class.name)
76
+ )
68
77
  end
69
- relation = relation.where(parts.join(" OR "), *binds) if parts.any?
78
+ relation = relation.merge(contact_relation) if email || user
70
79
 
71
80
  relation =
72
81
  if options[:list]
@@ -78,25 +87,33 @@ module Mailkick
78
87
  relation
79
88
  end
80
89
 
90
+ # TODO use keyword arguments
81
91
  def self.opted_out_emails(options = {})
82
- Set.new(opt_outs(options).where("email IS NOT NULL").uniq.pluck(:email))
92
+ Set.new(opt_outs(options).where.not(email: nil).distinct.pluck(:email))
83
93
  end
84
94
 
95
+ # TODO use keyword arguments
85
96
  # does not take into account emails
86
97
  def self.opted_out_users(options = {})
87
- Set.new(opt_outs(options).where("user_id IS NOT NULL").map(&:user))
98
+ Set.new(opt_outs(options).where.not(user_id: nil).map(&:user))
88
99
  end
89
100
 
90
101
  def self.message_verifier
91
102
  @message_verifier ||= ActiveSupport::MessageVerifier.new(Mailkick.secret_token)
92
103
  end
93
104
 
94
- def self.generate_token(email, list: nil)
95
- user = Mailkick.user_method.call(email) if Mailkick.user_method
105
+ def self.generate_token(email, user: nil, list: nil)
106
+ raise ArgumentError, "Missing email" unless email
107
+
108
+ user ||= Mailkick.user_method.call(email) if Mailkick.user_method
96
109
  message_verifier.generate([email, user.try(:id), user.try(:class).try(:name), list])
97
110
  end
98
111
  end
99
112
 
113
+ ActiveSupport.on_load :action_mailer do
114
+ helper Mailkick::UrlHelper
115
+ end
116
+
100
117
  ActiveSupport.on_load(:active_record) do
101
118
  extend Mailkick::Model
102
119
  end
@@ -7,7 +7,7 @@ module Mailkick
7
7
 
8
8
  Mailkick.secret_token ||= begin
9
9
  creds =
10
- if app.respond_to?(:credentials)
10
+ if app.respond_to?(:credentials) && app.credentials.secret_key_base
11
11
  app.credentials
12
12
  elsif app.respond_to?(:secrets)
13
13
  app.secrets
@@ -17,10 +17,6 @@ module Mailkick
17
17
 
18
18
  creds.respond_to?(:secret_key_base) ? creds.secret_key_base : creds.secret_token
19
19
  end
20
-
21
- ActiveSupport.on_load :action_mailer do
22
- helper Mailkick::UrlHelper
23
- end
24
20
  end
25
21
  end
26
22
  end
@@ -3,8 +3,8 @@ module Mailkick
3
3
  def mailkick_user(opts = {})
4
4
  email_key = opts[:email_key] || :email
5
5
  class_eval do
6
- scope :opted_out, proc {|options = {}|
7
- binds = [self.class.name, true]
6
+ scope :opted_out, lambda { |options = {}|
7
+ binds = [name, true]
8
8
  if options[:list]
9
9
  query = "(mailkick_opt_outs.list IS NULL OR mailkick_opt_outs.list = ?)"
10
10
  binds << options[:list]
@@ -13,20 +13,21 @@ module Mailkick
13
13
  end
14
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
15
  }
16
- scope :not_opted_out, proc {|options = {}|
16
+
17
+ scope :not_opted_out, lambda { |options = {}|
17
18
  opted_out(options.merge(not: true))
18
19
  }
19
20
 
20
- def opted_out?(options = {})
21
- Mailkick.opted_out?({email: email, user: self}.merge(options))
21
+ define_method :opted_out? do |options = {}|
22
+ Mailkick.opted_out?({email: send(email_key), user: self}.merge(options))
22
23
  end
23
24
 
24
- def opt_out(options = {})
25
- Mailkick.opt_out({email: email, user: self}.merge(options))
25
+ define_method :opt_out do |options = {}|
26
+ Mailkick.opt_out({email: send(email_key), user: self}.merge(options))
26
27
  end
27
28
 
28
- def opt_in(options = {})
29
- Mailkick.opt_in({email: email, user: self}.merge(options))
29
+ define_method :opt_in do |options = {}|
30
+ Mailkick.opt_in({email: send(email_key), user: self}.merge(options))
30
31
  end
31
32
  end
32
33
  end
@@ -0,0 +1,47 @@
1
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html
2
+
3
+ module Mailkick
4
+ class Service
5
+ class AwsSes < Mailkick::Service
6
+ REASONS_MAP = {
7
+ "BOUNCE" => "bounce",
8
+ "COMPLAINT" => "spam"
9
+ }
10
+
11
+ def initialize(options = {})
12
+ @options = options
13
+ end
14
+
15
+ def opt_outs
16
+ response = client.list_suppressed_destinations({
17
+ reasons: ["BOUNCE", "COMPLAINT"],
18
+ # TODO make configurable
19
+ start_date: Time.now - (86400 * 365),
20
+ end_date: Time.now
21
+ })
22
+
23
+ opt_outs = []
24
+ response.each do |page|
25
+ page.suppressed_destination_summaries.each do |record|
26
+ opt_outs << {
27
+ email: record.email_address,
28
+ time: record.last_update_time,
29
+ reason: REASONS_MAP[record.reason]
30
+ }
31
+ end
32
+ end
33
+ opt_outs
34
+ end
35
+
36
+ def self.discoverable?
37
+ !!defined?(::Aws::SESV2::Client)
38
+ end
39
+
40
+ private
41
+
42
+ def client
43
+ @client ||= ::Aws::SESV2::Client.new
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,41 @@
1
+ # https://github.com/wildbit/postmark-gem
2
+
3
+ module Mailkick
4
+ class Service
5
+ class Postmark < Mailkick::Service
6
+ REASONS_MAP = {
7
+ "SpamNotification" => "spam",
8
+ "SpamComplaint" => "spam",
9
+ "Unsubscribe" => "unsubscribe",
10
+ }
11
+
12
+ def initialize(options = {})
13
+ @client = ::Postmark::ApiClient.new(options[:api_key] || ENV["POSTMARK_API_KEY"])
14
+ end
15
+
16
+ def opt_outs
17
+ bounces
18
+ end
19
+
20
+ def bounces
21
+ fetch(@client.bounces)
22
+ end
23
+
24
+ def self.discoverable?
25
+ !!(defined?(::Postmark) && ENV["POSTMARK_API_KEY"])
26
+ end
27
+
28
+ protected
29
+
30
+ def fetch(response)
31
+ response.map do |record|
32
+ {
33
+ email: record[:email],
34
+ time: ActiveSupport::TimeZone["UTC"].parse(record[:bounced_at]),
35
+ reason: REASONS_MAP.fetch(record[:type], "bounce")
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Mailkick
4
4
  class Service
5
- class Sendgrid < Mailkick::Service
5
+ class SendGrid < Mailkick::Service
6
6
  def initialize(options = {})
7
7
  @api_user = options[:api_user] || ENV["SENDGRID_USERNAME"]
8
8
  @api_key = options[:api_key] || ENV["SENDGRID_PASSWORD"]
@@ -41,5 +41,8 @@ module Mailkick
41
41
  end
42
42
  end
43
43
  end
44
+
45
+ # backwards compatibility
46
+ Sendgrid = SendGrid
44
47
  end
45
48
  end
@@ -0,0 +1,52 @@
1
+ # https://github.com/sendgrid/sendgrid-ruby
2
+
3
+ module Mailkick
4
+ class Service
5
+ class SendGridV2 < Mailkick::Service
6
+ def initialize(options = {})
7
+ @api_key = options[:api_key] || ENV["SENDGRID_API_KEY"]
8
+ end
9
+
10
+ def opt_outs
11
+ unsubscribes + spam_reports + bounces
12
+ end
13
+
14
+ def unsubscribes
15
+ fetch(client.suppression.unsubscribes, "unsubscribe")
16
+ end
17
+
18
+ def spam_reports
19
+ fetch(client.suppression.spam_reports, "spam")
20
+ end
21
+
22
+ def bounces
23
+ fetch(client.suppression.bounces, "bounce")
24
+ end
25
+
26
+ def self.discoverable?
27
+ !!(defined?(::SendGrid::API) && ENV["SENDGRID_API_KEY"])
28
+ end
29
+
30
+ protected
31
+
32
+ def client
33
+ @client ||= ::SendGrid::API.new(api_key: @api_key).client
34
+ end
35
+
36
+ def fetch(query, reason)
37
+ # TODO paginate
38
+ response = query.get
39
+
40
+ raise "Bad status code: #{response.status_code}" if response.status_code.to_i != 200
41
+
42
+ response.parsed_body.map do |record|
43
+ {
44
+ email: record[:email],
45
+ time: Time.at(record[:created]),
46
+ reason: reason
47
+ }
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,12 +1,13 @@
1
1
  module Mailkick
2
2
  module UrlHelper
3
- def mailkick_unsubscribe_url(email: nil, list: nil, **options)
4
- email ||= controller.message.to.first
3
+ def mailkick_unsubscribe_url(email: nil, user: nil, list: nil, **options)
4
+ email ||= controller.try(:message).try(:to).try(:first)
5
+
5
6
  Mailkick::Engine.routes.url_helpers.url_for(
6
7
  (ActionMailer::Base.default_url_options || {}).merge(options).merge(
7
8
  controller: "mailkick/subscriptions",
8
9
  action: "unsubscribe",
9
- id: Mailkick.generate_token(email, list: list)
10
+ id: Mailkick.generate_token(email, user: user, list: list)
10
11
  )
11
12
  )
12
13
  end
@@ -1,3 +1,3 @@
1
1
  module Mailkick
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.3"
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.3.0
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-20 00:00:00.000000000 Z
11
+ date: 2020-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '5'
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: '4.2'
26
+ version: '5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
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'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: combustion
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -164,54 +178,40 @@ dependencies:
164
178
  - - ">="
165
179
  - !ruby/object:Gem::Version
166
180
  version: '0'
167
- description:
168
- email:
169
- - andrew@chartkick.com
181
+ description:
182
+ email: andrew@chartkick.com
170
183
  executables: []
171
184
  extensions: []
172
185
  extra_rdoc_files: []
173
186
  files:
174
- - ".gitignore"
175
- - ".travis.yml"
176
187
  - CHANGELOG.md
177
- - Gemfile
178
188
  - LICENSE.txt
179
189
  - README.md
180
- - Rakefile
181
190
  - app/controllers/mailkick/subscriptions_controller.rb
182
- - app/helpers/mailkick/url_helper.rb
183
191
  - app/models/mailkick/opt_out.rb
184
192
  - app/views/mailkick/subscriptions/show.html.erb
185
193
  - config/routes.rb
186
194
  - lib/generators/mailkick/install_generator.rb
187
- - lib/generators/mailkick/templates/install.rb
195
+ - lib/generators/mailkick/templates/install.rb.tt
188
196
  - lib/generators/mailkick/views_generator.rb
189
197
  - lib/mailkick.rb
190
198
  - lib/mailkick/engine.rb
191
199
  - lib/mailkick/model.rb
192
200
  - lib/mailkick/service.rb
201
+ - lib/mailkick/service/aws_ses.rb
193
202
  - lib/mailkick/service/mailchimp.rb
194
203
  - lib/mailkick/service/mailgun.rb
195
204
  - lib/mailkick/service/mandrill.rb
205
+ - lib/mailkick/service/postmark.rb
196
206
  - lib/mailkick/service/sendgrid.rb
207
+ - lib/mailkick/service/sendgrid_v2.rb
208
+ - lib/mailkick/url_helper.rb
197
209
  - lib/mailkick/version.rb
198
- - mailkick.gemspec
199
- - test/gemfiles/actionmailer42.gemfile
200
- - test/gemfiles/actionmailer50.gemfile
201
- - test/gemfiles/actionmailer51.gemfile
202
- - test/internal/app/mailers/user_mailer.rb
203
- - test/internal/app/models/user.rb
204
- - test/internal/app/views/user_mailer/welcome.html.erb
205
- - test/internal/app/views/user_mailer/welcome.text.erb
206
- - test/internal/config/database.yml
207
- - test/internal/db/schema.rb
208
- - test/mailkick_test.rb
209
- - test/test_helper.rb
210
210
  homepage: https://github.com/ankane/mailkick
211
211
  licenses:
212
212
  - MIT
213
213
  metadata: {}
214
- post_install_message:
214
+ post_install_message:
215
215
  rdoc_options: []
216
216
  require_paths:
217
217
  - lib
@@ -219,27 +219,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
219
219
  requirements:
220
220
  - - ">="
221
221
  - !ruby/object:Gem::Version
222
- version: '0'
222
+ version: '2.4'
223
223
  required_rubygems_version: !ruby/object:Gem::Requirement
224
224
  requirements:
225
225
  - - ">="
226
226
  - !ruby/object:Gem::Version
227
227
  version: '0'
228
228
  requirements: []
229
- rubyforge_project:
230
- rubygems_version: 2.7.6
231
- signing_key:
229
+ rubygems_version: 3.1.4
230
+ signing_key:
232
231
  specification_version: 4
233
- summary: Email subscriptions made easy
234
- test_files:
235
- - test/gemfiles/actionmailer42.gemfile
236
- - test/gemfiles/actionmailer50.gemfile
237
- - test/gemfiles/actionmailer51.gemfile
238
- - test/internal/app/mailers/user_mailer.rb
239
- - test/internal/app/models/user.rb
240
- - test/internal/app/views/user_mailer/welcome.html.erb
241
- - test/internal/app/views/user_mailer/welcome.text.erb
242
- - test/internal/config/database.yml
243
- - test/internal/db/schema.rb
244
- - test/mailkick_test.rb
245
- - test/test_helper.rb
232
+ summary: Email unsubscribes for Rails
233
+ test_files: []
data/.gitignore DELETED
@@ -1,24 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
18
- *.bundle
19
- *.so
20
- *.o
21
- *.a
22
- mkmf.log
23
- *.log
24
- *.sqlite
@@ -1,16 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.4.2
4
- sudo: false
5
- script: bundle exec rake test
6
- before_script:
7
- - gem install bundler
8
- notifications:
9
- email:
10
- on_success: never
11
- on_failure: change
12
- gemfile:
13
- - Gemfile
14
- - test/gemfiles/actionmailer51.gemfile
15
- - test/gemfiles/actionmailer50.gemfile
16
- - test/gemfiles/actionmailer42.gemfile
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in mailkick.gemspec
4
- gemspec
5
-
6
- gem "actionmailer", "~> 5.2.0"
data/Rakefile DELETED
@@ -1,9 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- task default: :test
5
- Rake::TestTask.new do |t|
6
- t.libs << "test"
7
- t.pattern = "test/**/*_test.rb"
8
- t.warning = false
9
- end
@@ -1,32 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "mailkick/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "mailkick"
8
- spec.version = Mailkick::VERSION
9
- spec.authors = ["Andrew Kane"]
10
- spec.email = ["andrew@chartkick.com"]
11
- spec.summary = "Email subscriptions made easy"
12
- spec.homepage = "https://github.com/ankane/mailkick"
13
- spec.license = "MIT"
14
-
15
- spec.files = `git ls-files -z`.split("\x0")
16
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib"]
19
-
20
- spec.add_dependency "activesupport", ">= 4.2"
21
-
22
- spec.add_development_dependency "bundler"
23
- spec.add_development_dependency "gibbon", ">= 2"
24
- spec.add_development_dependency "mailgun-ruby"
25
- spec.add_development_dependency "mandrill-api"
26
- spec.add_development_dependency "minitest"
27
- spec.add_development_dependency "rake"
28
- spec.add_development_dependency "sendgrid_toolkit"
29
- spec.add_development_dependency "combustion"
30
- spec.add_development_dependency "rails"
31
- spec.add_development_dependency "sqlite3"
32
- end
@@ -1,6 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in mailkick.gemspec
4
- gemspec path: "../../"
5
-
6
- gem "actionmailer", "~> 4.2.0"
@@ -1,6 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in mailkick.gemspec
4
- gemspec path: "../../"
5
-
6
- gem "actionmailer", "~> 5.0.0"
@@ -1,6 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in mailkick.gemspec
4
- gemspec path: "../../"
5
-
6
- gem "actionmailer", "~> 5.1.0"
@@ -1,7 +0,0 @@
1
- class UserMailer < ActionMailer::Base
2
- default from: "from@example.com"
3
-
4
- def welcome
5
- mail to: "test@example.org", subject: "Hello"
6
- end
7
- end
@@ -1,3 +0,0 @@
1
- class User < ActiveRecord::Base
2
- mailkick_user
3
- end
@@ -1 +0,0 @@
1
- <p><%= mailkick_unsubscribe_url %></p>
@@ -1 +0,0 @@
1
- Unsubscribe: <%= mailkick_unsubscribe_url %>
@@ -1,3 +0,0 @@
1
- test:
2
- adapter: sqlite3
3
- database: db/combustion_test.sqlite
@@ -1,16 +0,0 @@
1
- ActiveRecord::Schema.define do
2
- create_table :mailkick_opt_outs do |t|
3
- t.string :email
4
- t.references :user, polymorphic: true
5
- t.boolean :active, null: false, default: true
6
- t.string :reason
7
- t.string :list
8
- t.timestamps
9
- end
10
-
11
- add_index :mailkick_opt_outs, :email
12
-
13
- create_table :users do |t|
14
- t.string :email
15
- end
16
- end
@@ -1,29 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class MailkickTest < Minitest::Test
4
- def test_unsubscribe_url
5
- message = UserMailer.welcome.deliver_now
6
- html_body = message.html_part.body.to_s
7
- assert_includes html_body, "BAhbCUkiFXRlc3RAZXhhbXBsZS5vcmcGOgZFVDAwMA==--f435e91ba90e1732d3e999af1f2126dcc8182a5d"
8
- text_body = message.text_part.body.to_s
9
- assert_includes text_body, "BAhbCUkiFXRlc3RAZXhhbXBsZS5vcmcGOgZFVDAwMA==--f435e91ba90e1732d3e999af1f2126dcc8182a5d"
10
- end
11
-
12
- def test_opt_out
13
- email = "test2@example.org"
14
- user = User.create!(email: email)
15
-
16
- Mailkick.opt_out(email: email, user: user)
17
-
18
- opt_outs = Mailkick::OptOut.all.to_a
19
- assert_equal 1, opt_outs.size
20
-
21
- opt_out = opt_outs.first
22
- assert_equal email, opt_out.email
23
- assert_equal user, opt_out.user
24
-
25
- assert user.opted_out?
26
- assert_equal 1, User.opted_out.count
27
- assert_equal 0, User.not_opted_out.count
28
- end
29
- end
@@ -1,20 +0,0 @@
1
- require "bundler/setup"
2
- require "combustion"
3
- Bundler.require(:default)
4
- require "minitest/autorun"
5
- require "minitest/pride"
6
- require "logger"
7
-
8
- Minitest::Test = Minitest::Unit::TestCase unless defined?(Minitest::Test)
9
-
10
- Combustion.path = "test/internal"
11
- Combustion.initialize! :all do
12
- if config.active_record.sqlite3.respond_to?(:represent_boolean_as_integer)
13
- config.active_record.sqlite3.represent_boolean_as_integer = false
14
- end
15
- end
16
-
17
- ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT) if ENV["VERBOSE"]
18
- ActionMailer::Base.delivery_method = :test
19
-
20
- Mailkick.secret_token = "test123"