ahoy_email 0.5.2 → 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: 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