ahoy_email 0.5.2 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1bd419ac1420c0d404b6137e3804545193969ecd8aab0444c919e9f7b5e5fae4
4
- data.tar.gz: 3cce5d71d203a287992fc6560910f596f3cf74b0ef24861df8f5ed27ad9bd3b1
3
+ metadata.gz: acb3c3744cff970d75c695f1c79edec32e7dd7a9bea7342576b7fc87be2d3e4a
4
+ data.tar.gz: 1cd08f10de1fa686aa09312cdee054694debe9f7835bb97fd9eb35aa9fc09c01
5
5
  SHA512:
6
- metadata.gz: b163a83c5a2f78e7a2576940f1d7d0bb25bb38fec0203571adf387ffa2e380c5ed164fff92ba12c00f81a30d7b43b39e41d7a68a1d94b86f2dfc27c48139eb16
7
- data.tar.gz: 816a961760e8fedf55efa9b5b59f38decdf0fdd12531dc5a52f83c09178bddf820e93eb375c47100e10bd4e9f2aba7b4c2efabde952ebfc589cf20d2d0418537
6
+ metadata.gz: 3eb7a246d87edfec081d873c8a464c90a682b81acd5d38877c8551770ba911f0c222bf778b03c2abf390fadf5bf48edabe863187627740c673b86718e082a9e4
7
+ data.tar.gz: 15c5a59995db66c0d76bfa5273e8a7f4404b11d80078fbf73765fcfb157d8ed3ff744b7bc694e75c8eb8fc2b4afc5494727fa68fb2f60769f91cf2d1f86e7dec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 1.0.0
2
+
3
+ - Removed support for Rails < 4.2
4
+
5
+ Breaking changes
6
+
7
+ - UTM tagging, open tracking, and click tracking are no longer enabled by default
8
+ - Only sent emails are recorded
9
+ - Proc options are now executed in the context of the mailer and take no arguments
10
+ - Invalid options now throw an `ArgumentError`
11
+ - `AhoyEmail.track` was removed in favor of `AhoyEmail.default_options`
12
+ - The `heuristic_parse` option was removed and is now the default
13
+
1
14
  ## 0.5.2
2
15
 
3
16
  - Fixed secret token for Rails 5.2
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,47 @@
1
+ # Contributing
2
+
3
+ First, thanks for wanting to contribute. You’re awesome! :heart:
4
+
5
+ ## Help
6
+
7
+ We’re not able to provide support through GitHub Issues. If you’re looking for help with your code, try posting on [Stack Overflow](https://stackoverflow.com/).
8
+
9
+ All features should be documented. If you don’t see a feature in the docs, assume it doesn’t exist.
10
+
11
+ ## Bugs
12
+
13
+ Think you’ve discovered a bug?
14
+
15
+ 1. Search existing issues to see if it’s been reported.
16
+ 2. Try the `master` branch to make sure it hasn’t been fixed.
17
+
18
+ ```rb
19
+ gem "ahoy_email", github: "ankane/ahoy_email"
20
+ ```
21
+
22
+ If the above steps don’t help, create an issue. Include:
23
+
24
+ - Detailed steps to reproduce
25
+ - Complete backtraces for exceptions
26
+
27
+ ## New Features
28
+
29
+ If you’d like to discuss a new feature, create an issue and start the title with `[Idea]`.
30
+
31
+ ## Pull Requests
32
+
33
+ Fork the project and create a pull request. A few tips:
34
+
35
+ - Keep changes to a minimum. If you have multiple features or fixes, submit multiple pull requests.
36
+ - Follow the existing style. The code should read like it’s written by a single person.
37
+ - Add one or more tests if possible. Make sure existing tests pass with:
38
+
39
+ ```sh
40
+ bundle exec rake test
41
+ ```
42
+
43
+ Feel free to open an issue to get feedback on your idea before spending too much time on it.
44
+
45
+ ---
46
+
47
+ This contributing guide is released under [CCO](https://creativecommons.org/publicdomain/zero/1.0/) (public domain). Use it for your own project without attribution.
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Andrew Kane
1
+ Copyright (c) 2014-2018 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # Ahoy Email
2
2
 
3
- :postbox: Simple, powerful email tracking for Rails
3
+ :postbox: Email analytics for Rails
4
4
 
5
5
  You get:
6
6
 
7
7
  - A history of emails sent to each user
8
8
  - Easy UTM tagging
9
- - Open and click tracking
9
+ - Optional open and click tracking
10
10
 
11
- Works with any email service.
11
+ **Ahoy Email 1.0 was recently released!** See [how to upgrade](#upgrading)
12
12
 
13
13
  :bullettrain_side: To manage unsubscribes, check out [Mailkick](https://github.com/ankane/mailkick)
14
14
 
@@ -33,27 +33,37 @@ rails db:migrate
33
33
 
34
34
  ## How It Works
35
35
 
36
- Ahoy creates an `Ahoy::Message` every time an email is sent by default.
36
+ ### Message History
37
+
38
+ Ahoy creates an `Ahoy::Message` record for each email sent by default. You can disable history for a mailer:
39
+
40
+ ```ruby
41
+ class UserMailer < ApplicationMailer
42
+ track message: false # use only/except to limit actions
43
+ end
44
+ ```
45
+
46
+ Or by default:
47
+
48
+ ```ruby
49
+ AhoyEmail.default_options[:message] = false
50
+ ```
37
51
 
38
52
  ### Users
39
53
 
40
- Ahoy tracks the user a message is sent to - not just the email address. This gives you a full history of messages for each user, even if he or she changes addresses.
54
+ Ahoy records the user a message is sent to - not just the email address. This gives you a full history of messages for each user, even if he or she changes addresses.
41
55
 
42
- By default, Ahoy tries `User.where(email: message.to.first).first` to find the user.
56
+ By default, Ahoy tries `@user` then `params[:user]` then `User.find_by(email: message.to.first)` to find the user.
43
57
 
44
58
  You can pass a specific user with:
45
59
 
46
60
  ```ruby
47
61
  class UserMailer < ApplicationMailer
48
- def welcome_email(user)
49
- # ...
50
- track user: user
51
- mail to: user.email
52
- end
62
+ track user: -> { params[:some_user] }
53
63
  end
54
64
  ```
55
65
 
56
- The user association is [polymorphic](http://railscasts.com/episodes/154-polymorphic-association), so use it with any model.
66
+ The user association is [polymorphic](https://railscasts.com/episodes/154-polymorphic-association), so use it with any model.
57
67
 
58
68
  To get all messages sent to a user, add an association:
59
69
 
@@ -69,124 +79,148 @@ And run:
69
79
  user.messages
70
80
  ```
71
81
 
72
- ### UTM Parameters
82
+ ### Extra Attributes
73
83
 
74
- UTM parameters are added to links if they don’t already exist.
84
+ Record extra attributes on the `Ahoy::Message` model.
75
85
 
76
- The defaults are:
86
+ Create a migration to add extra attributes to the `ahoy_messages` table. For example:
77
87
 
78
- - utm_medium - `email`
79
- - utm_source - the mailer name like `user_mailer`
80
- - utm_campaign - the mailer action like `welcome_email`
88
+ ```ruby
89
+ class AddCouponIdToAhoyMessages < ActiveRecord::Migration[5.2]
90
+ def change
91
+ add_column :ahoy_messages, :coupon_id, :integer
92
+ end
93
+ end
94
+ ```
81
95
 
82
- Use `track utm_params: false` to skip tagging, or skip specific links with:
96
+ Then use:
83
97
 
98
+ ```ruby
99
+ class CouponMailer < ApplicationMailer
100
+ track extra: {coupon_id: 1}
101
+ end
102
+ ```
103
+
104
+ You can use a proc as well.
84
105
 
85
- ```html
86
- <a data-skip-utm-params="true" href="...">Break it down</a>
106
+ ```ruby
107
+ class CouponMailer < ApplicationMailer
108
+ track extra: -> { {coupon_id: params[:coupon].id} }
109
+ end
87
110
  ```
88
111
 
89
- ### Opens
112
+ ### UTM Tagging
90
113
 
91
- An invisible pixel is added right before the `</body>` tag in HTML emails.
114
+ Automatically add UTM parameters to links.
92
115
 
93
- If the recipient has images enabled in his or her email client, the pixel is loaded and the open time recorded.
116
+ ```ruby
117
+ class CouponMailer < ApplicationMailer
118
+ track utm_params: true # use only/except to limit actions
119
+ end
120
+ ```
94
121
 
95
- Use `track open: false` to skip this.
122
+ The defaults are:
96
123
 
97
- ### Clicks
124
+ - `utm_medium` - `email`
125
+ - `utm_source` - the mailer name like `coupon_mailer`
126
+ - `utm_campaign` - the mailer action like `offer`
98
127
 
99
- A redirect is added to links to track clicks in HTML emails.
128
+ You can customize them with:
100
129
 
101
- ```
102
- https://chartkick.com
130
+ ```ruby
131
+ class CouponMailer < ApplicationMailer
132
+ track utm_params: true, utm_campaign: -> { "coupon#{params[:coupon].id}" }
133
+ end
103
134
  ```
104
135
 
105
- becomes
136
+ Skip specific links with:
106
137
 
138
+ ```erb
139
+ <%= link_to "Go", some_url, data: {skip_utm_params: true} %>
107
140
  ```
108
- https://yoursite.com/ahoy/messages/rAnDoMtOkEn/click?url=https%3A%2F%2Fchartkick.com&signature=...
109
- ```
110
-
111
- A signature is added to prevent [open redirects](https://www.owasp.org/index.php/Open_redirect).
112
141
 
113
- Use `track click: false` to skip tracking, or skip specific links with:
142
+ ### Opens & Clicks
114
143
 
115
- ```html
116
- <a data-skip-click="true" href="...">Can't touch this</a>
117
- ```
144
+ #### Setup
118
145
 
119
- ### Extra Attributes
146
+ Additional setup is required to track opens and clicks.
120
147
 
121
- Create a migration to add extra attributes to the `ahoy_messages` table, for example:
148
+ Create a migration with:
122
149
 
123
150
  ```ruby
124
- class AddCampaignIdToAhoyMessages < ActiveRecord::Migration
151
+ class AddTokenToAhoyMessages < ActiveRecord::Migration[5.2]
125
152
  def change
126
- add_column :ahoy_messages, :campaign_id, :integer
153
+ add_column :ahoy_messages, :token, :string
154
+ add_column :ahoy_messages, :opened_at, :timestamp
155
+ add_column :ahoy_messages, :clicked_at, :timestamp
156
+
157
+ add_index :ahoy_messages, :token
127
158
  end
128
159
  end
129
160
  ```
130
161
 
131
- Then use:
162
+ Create an initializer `config/initializers/ahoy_email.rb` with:
132
163
 
133
164
  ```ruby
134
- track extra: {campaign_id: 1}
165
+ AhoyEmail.api = true
135
166
  ```
136
167
 
137
- ## Customize
168
+ And add to mailers you want to track:
138
169
 
139
- ### Tracking
170
+ ```ruby
171
+ class UserMailer < ApplicationMailer
172
+ track open: true, click: true # use only/except to limit actions
173
+ end
174
+ ```
140
175
 
141
- Skip tracking of attributes by removing them from your model. You can safely remove:
176
+ #### How It Works
142
177
 
143
- - to
144
- - mailer
145
- - subject
146
- - content
178
+ For opens, an invisible pixel is added right before the `</body>` tag in HTML emails. If the recipient has images enabled in their email client, the pixel is loaded and the open time recorded.
147
179
 
148
- ### Configuration
180
+ For clicks, a redirect is added to links to track clicks in HTML emails.
149
181
 
150
- There are 3 places to set options. Here’s the order of precedence.
182
+ ```
183
+ https://chartkick.com
184
+ ```
151
185
 
152
- #### Action
186
+ becomes
153
187
 
154
- ``` ruby
155
- class UserMailer < ApplicationMailer
156
- def welcome_email(user)
157
- # ...
158
- track user: user
159
- mail to: user.email
160
- end
161
- end
162
188
  ```
189
+ https://yoursite.com/ahoy/messages/rAnDoMtOkEn/click?url=https%3A%2F%2Fchartkick.com&signature=...
190
+ ```
191
+
192
+ A signature is added to prevent [open redirects](https://www.owasp.org/index.php/Open_redirect).
163
193
 
164
- #### Mailer
194
+ Skip specific links with:
195
+
196
+ ```erb
197
+ <%= link_to "Go", some_url, data: {skip_click: true} %>
198
+ ```
199
+
200
+ By default, unsubscribe links are excluded. To change this, use:
165
201
 
166
202
  ```ruby
167
- class UserMailer < ApplicationMailer
168
- track utm_campaign: "boom"
169
- end
203
+ AhoyEmail.default_options[:unsubscribe_links] = true
170
204
  ```
171
205
 
172
- #### Global
206
+ You can specify the domain to use with:
173
207
 
174
208
  ```ruby
175
- AhoyEmail.track open: false
209
+ AhoyEmail.default_options[:url_options] = {host: "mydomain.com"}
176
210
  ```
177
211
 
178
- ## Events
212
+ #### Events
179
213
 
180
- Subscribe to open and click events. Create an initializer `config/initializers/ahoy_email.rb` with:
214
+ Subscribe to open and click events by adding to the initializer:
181
215
 
182
216
  ```ruby
183
217
  class EmailSubscriber
184
218
  def open(event)
185
- # any code you want
219
+ # your code
186
220
  end
187
221
 
188
222
  def click(event)
189
- # any code you want
223
+ # your code
190
224
  end
191
225
  end
192
226
 
@@ -211,54 +245,56 @@ AhoyEmail.subscribers << EmailSubscriber.new
211
245
 
212
246
  ## Reference
213
247
 
214
- You can use a `Proc` for any option.
248
+ Set global options
215
249
 
216
250
  ```ruby
217
- track utm_campaign: ->(message, mailer) { mailer.action_name + Time.now.year }
251
+ AhoyEmail.default_options[:user] = -> { params[:admin] }
218
252
  ```
219
253
 
220
- Disable tracking for an email
254
+ Use a different model
221
255
 
222
256
  ```ruby
223
- track message: false
257
+ AhoyEmail.message_model = -> { UserMessage }
224
258
  ```
225
259
 
226
- Or specific actions
260
+ Or fully customize how messages are tracked
227
261
 
228
262
  ```ruby
229
- track only: [:welcome_email]
230
- track except: [:welcome_email]
263
+ AhoyEmail.track_method = lambda do |data|
264
+ # your code
265
+ end
231
266
  ```
232
267
 
233
- Or by default
268
+ ## Upgrading
234
269
 
235
- ```ruby
236
- AhoyEmail.track message: false
237
- ```
270
+ ### 1.0
238
271
 
239
- Customize domain
272
+ Breaking changes
240
273
 
241
- ```ruby
242
- track url_options: {host: "mydomain.com"}
243
- ```
274
+ - UTM tagging, open tracking, and click tracking are no longer enabled by default. To enable, create an initializer with:
244
275
 
245
- By default, unsubscribe links are excluded from tracking. To change this, use:
276
+ ```ruby
277
+ AhoyEmail.api = true
246
278
 
247
- ```ruby
248
- track unsubscribe_links: true
249
- ```
279
+ AhoyEmail.default_options[:open] = true
280
+ AhoyEmail.default_options[:click] = true
281
+ AhoyEmail.default_options[:utm_params] = true
282
+ ```
250
283
 
251
- Use a different model
284
+ - Only sent emails are recorded
285
+ - Proc options are now executed in the context of the mailer and take no arguments
252
286
 
253
- ```ruby
254
- AhoyEmail.message_model = -> { UserMessage }
255
- ```
256
-
257
- ## Upgrading
287
+ ```ruby
288
+ # old
289
+ user: ->(mailer, message) { User.find_by(email: message.to.first) }
258
290
 
259
- ### 0.2.3
291
+ # new
292
+ user: -> { User.find_by(email: message.to.first) }
293
+ ```
260
294
 
261
- Optionally, you can store UTM parameters by adding `utm_source`, `utm_medium`, and `utm_campaign` columns to your message model.
295
+ - Invalid options now throw an `ArgumentError`
296
+ - `AhoyEmail.track` was removed in favor of `AhoyEmail.default_options`
297
+ - The `heuristic_parse` option was removed and is now the default
262
298
 
263
299
  ## History
264
300
 
@@ -1,17 +1,24 @@
1
1
  module Ahoy
2
- class MessagesController < ActionController::Base
3
- if respond_to? :before_action
4
- before_action :set_message
2
+ class MessagesController < ApplicationController
3
+ filters = _process_action_callbacks.map(&:filter) - AhoyEmail.preserve_callbacks
4
+ if Rails::VERSION::MAJOR >= 5
5
+ skip_before_action(*filters, raise: false)
6
+ skip_after_action(*filters, raise: false)
7
+ skip_around_action(*filters, raise: false)
5
8
  else
6
- before_filter :set_message
9
+ skip_action_callback *filters
7
10
  end
8
11
 
12
+ before_action :set_message
13
+
9
14
  def open
10
15
  if @message && !@message.opened_at
11
16
  @message.opened_at = Time.now
12
17
  @message.save!
13
18
  end
19
+
14
20
  publish :open
21
+
15
22
  send_data Base64.decode64("R0lGODlhAQABAPAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="), type: "image/gif", disposition: "inline"
16
23
  end
17
24
 
@@ -21,10 +28,17 @@ module Ahoy
21
28
  @message.opened_at ||= @message.clicked_at
22
29
  @message.save!
23
30
  end
31
+
32
+ user_signature = params[:signature].to_s
24
33
  url = params[:url].to_s
25
- signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), AhoyEmail.secret_token, url)
26
- publish :click, url: params[:url]
27
- if secure_compare(params[:signature].to_s, signature)
34
+
35
+ # TODO sign more than just url and transition to HMAC-SHA256
36
+ digest = "SHA1"
37
+ signature = OpenSSL::HMAC.hexdigest(digest, AhoyEmail.secret_token, url)
38
+
39
+ if ActiveSupport::SecurityUtils.secure_compare(user_signature, signature)
40
+ publish :click, url: params[:url]
41
+
28
42
  redirect_to url
29
43
  else
30
44
  redirect_to AhoyEmail.invalid_redirect_url || main_app.root_url
@@ -46,17 +60,5 @@ module Ahoy
46
60
  end
47
61
  end
48
62
  end
49
-
50
- # from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/message_verifier.rb
51
- # constant-time comparison algorithm to prevent timing attacks
52
- def secure_compare(a, b)
53
- return false unless a.bytesize == b.bytesize
54
-
55
- l = a.unpack "C#{a.bytesize}"
56
-
57
- res = 0
58
- b.each_byte { |byte| res |= byte ^ l.shift }
59
- res == 0
60
- end
61
63
  end
62
64
  end