ahoy_email 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +159 -147
- data/app/controllers/ahoy/messages_controller.rb +24 -49
- data/config/routes.rb +3 -0
- data/lib/ahoy_email.rb +33 -9
- data/lib/ahoy_email/mailer.rb +45 -17
- data/lib/ahoy_email/message_subscriber.rb +12 -0
- data/lib/ahoy_email/processor.rb +16 -45
- data/lib/ahoy_email/redis_subscriber.rb +79 -0
- data/lib/ahoy_email/tracker.rb +9 -3
- data/lib/ahoy_email/utils.rb +35 -0
- data/lib/ahoy_email/version.rb +1 -1
- data/lib/generators/ahoy/messages/activerecord_generator.rb +40 -0
- data/lib/generators/ahoy/messages/mongoid_generator.rb +21 -0
- data/lib/generators/{ahoy_email/templates/install.rb.tt → ahoy/messages/templates/migration.rb.tt} +1 -1
- data/lib/generators/ahoy/messages/templates/model_encrypted.rb.tt +8 -0
- data/lib/generators/ahoy/messages/templates/mongoid.rb.tt +12 -0
- data/lib/generators/ahoy/messages/templates/mongoid_encrypted.rb.tt +16 -0
- data/lib/generators/ahoy/messages_generator.rb +41 -0
- metadata +12 -88
- data/lib/generators/ahoy_email/install_generator.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d178d2bd4a2631bad0bce962cd35daecc019034270530f350596d14172e46ca0
|
4
|
+
data.tar.gz: af5eb88ec75a4100c5215a71e39fb825d7c7e4823fd601c3cd6473b7409db3dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcc3ac25d9a8323a4da3a4331a338ca377a375033886c9e447945654897ea3b89e178ffe7a4e02336838ba27e1b8f8dda0aef0f5261f1adb8c66167dbe758f98
|
7
|
+
data.tar.gz: b433434716662eb90d9309c6dfdefe61752496777206e43d1d1d9ddadfee9aa664cf1daa1272d4df62a393d6e979e62932194829dd68b84720fd47661fada6e0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## 2.0.0 (2021-03-06)
|
2
|
+
|
3
|
+
- Made `to` field encrypted by default for new installations
|
4
|
+
- Added click analytics for Redis
|
5
|
+
- Added send events to subscribers
|
6
|
+
- Removed support for Rails < 5.2
|
7
|
+
|
8
|
+
Breaking changes
|
9
|
+
|
10
|
+
- The `track` method has been broken into `has_history` for message history, `utm_params` for UTM tagging, and `track_clicks` for click analytics
|
11
|
+
- Message history is no longer enabled by default
|
12
|
+
- Open tracking has been removed
|
13
|
+
- `:message` is no longer included in click events
|
14
|
+
- Users are shown a link expired page when signature verification fails instead of being redirected to the homepage when `AhoyEmail.invalid_redirect_url` is not set
|
15
|
+
|
1
16
|
## 1.1.1 (2021-03-06)
|
2
17
|
|
3
18
|
- Added support for classes for subscribers
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
First-party email analytics for Rails
|
4
4
|
|
5
|
+
**Ahoy Email 2.0 was recently released** - see [how to upgrade](#upgrading)
|
6
|
+
|
5
7
|
:fire: For web and native app analytics, check out [Ahoy](https://github.com/ankane/ahoy)
|
6
8
|
|
7
9
|
:bullettrain_side: To manage unsubscribes, check out [Mailkick](https://github.com/ankane/mailkick)
|
@@ -16,48 +18,65 @@ Add this line to your application’s Gemfile:
|
|
16
18
|
gem 'ahoy_email'
|
17
19
|
```
|
18
20
|
|
19
|
-
And run the generator. This creates a model to store messages.
|
20
|
-
|
21
|
-
```sh
|
22
|
-
rails generate ahoy_email:install
|
23
|
-
rails db:migrate
|
24
|
-
```
|
25
|
-
|
26
21
|
## Getting Started
|
27
22
|
|
28
|
-
There are three main features:
|
23
|
+
There are three main features, which can be used independently:
|
29
24
|
|
30
25
|
- [Message history](#message-history)
|
31
26
|
- [UTM tagging](#utm-tagging)
|
32
|
-
- [
|
27
|
+
- [Click analytics](#click-analytics)
|
33
28
|
|
34
29
|
## Message History
|
35
30
|
|
36
|
-
|
31
|
+
To encrypt email addresses, install [Lockbox](https://github.com/ankane/lockbox) and [Blind Index](https://github.com/ankane/blind_index) and run:
|
32
|
+
|
33
|
+
```sh
|
34
|
+
rails generate ahoy:messages
|
35
|
+
rails db:migrate
|
36
|
+
```
|
37
|
+
|
38
|
+
If you prefer not to encrypt data, run:
|
39
|
+
|
40
|
+
```sh
|
41
|
+
rails generate ahoy:messages --unencrypted
|
42
|
+
rails db:migrate
|
43
|
+
```
|
44
|
+
|
45
|
+
Then, add to mailers:
|
37
46
|
|
38
47
|
```ruby
|
39
48
|
class CouponMailer < ApplicationMailer
|
40
|
-
|
49
|
+
has_history
|
41
50
|
end
|
42
51
|
```
|
43
52
|
|
44
|
-
|
53
|
+
Use the `Ahoy::Message` model to query messages:
|
45
54
|
|
46
55
|
```ruby
|
47
|
-
|
56
|
+
Ahoy::Message.last
|
48
57
|
```
|
49
58
|
|
50
|
-
|
59
|
+
Use only and except to limit actions
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
class CouponMailer < ApplicationMailer
|
63
|
+
has_history only: [:welcome]
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
To store history for all mailers, create `config/initializers/ahoy_email.rb` with:
|
51
68
|
|
52
|
-
|
69
|
+
```ruby
|
70
|
+
AhoyEmail.default_options[:message] = true
|
71
|
+
```
|
53
72
|
|
54
|
-
|
73
|
+
### Users
|
55
74
|
|
56
|
-
You can pass a specific user with:
|
75
|
+
By default, Ahoy Email tries `@user` then `params[:user]` then `User.find_by(email: message.to)` to find the user. You can pass a specific user with:
|
57
76
|
|
58
77
|
```ruby
|
59
78
|
class CouponMailer < ApplicationMailer
|
60
|
-
|
79
|
+
has_history user: -> { params[:some_user] }
|
61
80
|
end
|
62
81
|
```
|
63
82
|
|
@@ -77,11 +96,9 @@ And run:
|
|
77
96
|
user.messages
|
78
97
|
```
|
79
98
|
|
80
|
-
### Extra
|
99
|
+
### Extra Data
|
81
100
|
|
82
|
-
|
83
|
-
|
84
|
-
Create a migration to add extra attributes to the `ahoy_messages` table. For example:
|
101
|
+
Add extra data to messages. Create a migration like:
|
85
102
|
|
86
103
|
```ruby
|
87
104
|
class AddCouponIdToAhoyMessages < ActiveRecord::Migration[6.1]
|
@@ -91,11 +108,11 @@ class AddCouponIdToAhoyMessages < ActiveRecord::Migration[6.1]
|
|
91
108
|
end
|
92
109
|
```
|
93
110
|
|
94
|
-
|
111
|
+
And use:
|
95
112
|
|
96
113
|
```ruby
|
97
114
|
class CouponMailer < ApplicationMailer
|
98
|
-
|
115
|
+
has_history extra: {coupon_id: 1}
|
99
116
|
end
|
100
117
|
```
|
101
118
|
|
@@ -103,23 +120,53 @@ You can use a proc as well.
|
|
103
120
|
|
104
121
|
```ruby
|
105
122
|
class CouponMailer < ApplicationMailer
|
106
|
-
|
123
|
+
has_history extra: -> { {coupon_id: params[:coupon].id} }
|
107
124
|
end
|
108
125
|
```
|
109
126
|
|
110
|
-
|
127
|
+
### Options
|
111
128
|
|
112
|
-
|
129
|
+
Set global options
|
113
130
|
|
114
|
-
|
115
|
-
|
116
|
-
|
131
|
+
```ruby
|
132
|
+
AhoyEmail.default_options[:user] = -> { params[:admin] }
|
133
|
+
```
|
117
134
|
|
118
|
-
|
135
|
+
Use a different model
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
AhoyEmail.message_model = -> { UserMessage }
|
139
|
+
```
|
140
|
+
|
141
|
+
Or fully customize how messages are tracked
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
AhoyEmail.track_method = lambda do |data|
|
145
|
+
# your code
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
### Data Retention
|
150
|
+
|
151
|
+
Delete older data with:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
Ahoy::Message.where("created_at < ?", 1.year.ago).in_batches.delete_all
|
155
|
+
```
|
156
|
+
|
157
|
+
Delete data for a specific user with:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
Ahoy::Message.where(user_id: 1).in_batches.delete_all
|
161
|
+
```
|
162
|
+
|
163
|
+
## UTM Tagging
|
164
|
+
|
165
|
+
Use UTM tagging to attribute visits or conversions to an email campaign. Add UTM parameters to links with:
|
119
166
|
|
120
167
|
```ruby
|
121
168
|
class CouponMailer < ApplicationMailer
|
122
|
-
|
169
|
+
utm_params
|
123
170
|
end
|
124
171
|
```
|
125
172
|
|
@@ -133,7 +180,15 @@ You can customize them with:
|
|
133
180
|
|
134
181
|
```ruby
|
135
182
|
class CouponMailer < ApplicationMailer
|
136
|
-
|
183
|
+
utm_params utm_campaign: -> { "coupon#{params[:coupon].id}" }
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
Use only and except to limit actions
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
class CouponMailer < ApplicationMailer
|
191
|
+
utm_params only: [:welcome]
|
137
192
|
end
|
138
193
|
```
|
139
194
|
|
@@ -143,40 +198,56 @@ Skip specific links with:
|
|
143
198
|
<%= link_to "Go", some_url, data: {skip_utm_params: true} %>
|
144
199
|
```
|
145
200
|
|
146
|
-
##
|
201
|
+
## Click Analytics
|
147
202
|
|
148
|
-
|
203
|
+
You can track click-through rate to see how well campaigns are performing. Stats can be stored in any data store, and there’s a built-in integration with Redis.
|
149
204
|
|
150
|
-
|
205
|
+
#### Redis
|
151
206
|
|
152
|
-
|
207
|
+
Add this line to your application’s Gemfile:
|
153
208
|
|
154
209
|
```ruby
|
155
|
-
|
156
|
-
|
157
|
-
add_column :ahoy_messages, :token, :string
|
158
|
-
add_index :ahoy_messages, :token
|
210
|
+
gem 'redis'
|
211
|
+
```
|
159
212
|
|
160
|
-
|
161
|
-
add_column :ahoy_messages, :opened_at, :timestamp
|
213
|
+
And create `config/initializers/ahoy_email.rb` with:
|
162
214
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
215
|
+
```ruby
|
216
|
+
# pass your Redis client if you already have one
|
217
|
+
AhoyEmail.subscribers << AhoyEmail::RedisSubscriber.new(redis: Redis.new)
|
218
|
+
AhoyEmail.api = true
|
167
219
|
```
|
168
220
|
|
169
|
-
|
221
|
+
#### Other
|
222
|
+
|
223
|
+
Create `config/initializers/ahoy_email.rb` with:
|
170
224
|
|
171
225
|
```ruby
|
226
|
+
class EmailSubscriber
|
227
|
+
def track_send(data)
|
228
|
+
# your code
|
229
|
+
end
|
230
|
+
|
231
|
+
def track_click(data)
|
232
|
+
# your code
|
233
|
+
end
|
234
|
+
|
235
|
+
def stats(campaign = nil)
|
236
|
+
# optional, for AhoyEmail.stats
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
AhoyEmail.subscribers << EmailSubscriber
|
172
241
|
AhoyEmail.api = true
|
173
|
-
|
242
|
+
````
|
174
243
|
|
175
|
-
|
244
|
+
### Setup
|
245
|
+
|
246
|
+
Add to mailers you want to track
|
176
247
|
|
177
248
|
```ruby
|
178
249
|
class CouponMailer < ApplicationMailer
|
179
|
-
|
250
|
+
track_clicks campaign: "my-campaign"
|
180
251
|
end
|
181
252
|
```
|
182
253
|
|
@@ -184,7 +255,7 @@ Use only and except to limit actions
|
|
184
255
|
|
185
256
|
```ruby
|
186
257
|
class CouponMailer < ApplicationMailer
|
187
|
-
|
258
|
+
track_clicks campaign: "my-campaign", only: [:welcome]
|
188
259
|
end
|
189
260
|
```
|
190
261
|
|
@@ -192,28 +263,10 @@ Or make it conditional
|
|
192
263
|
|
193
264
|
```ruby
|
194
265
|
class CouponMailer < ApplicationMailer
|
195
|
-
|
266
|
+
track_clicks campaign: "my-campaign", if: -> { params[:user].opted_in? }
|
196
267
|
end
|
197
268
|
```
|
198
269
|
|
199
|
-
### How It Works
|
200
|
-
|
201
|
-
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.
|
202
|
-
|
203
|
-
For clicks, a redirect is added to links to track clicks in HTML emails.
|
204
|
-
|
205
|
-
```
|
206
|
-
https://chartkick.com
|
207
|
-
```
|
208
|
-
|
209
|
-
becomes
|
210
|
-
|
211
|
-
```
|
212
|
-
https://yoursite.com/ahoy/messages/rAnDoMtOkEn/click?url=https%3A%2F%2Fchartkick.com&signature=...
|
213
|
-
```
|
214
|
-
|
215
|
-
A signature is added to prevent [open redirects](https://www.owasp.org/index.php/Open_redirect).
|
216
|
-
|
217
270
|
Skip specific links with:
|
218
271
|
|
219
272
|
```erb
|
@@ -232,108 +285,67 @@ You can specify the domain to use with:
|
|
232
285
|
AhoyEmail.default_options[:url_options] = {host: "mydomain.com"}
|
233
286
|
```
|
234
287
|
|
235
|
-
###
|
288
|
+
### Stats
|
236
289
|
|
237
|
-
|
290
|
+
Get stats for all campaigns
|
238
291
|
|
239
292
|
```ruby
|
240
|
-
|
241
|
-
def open(event)
|
242
|
-
# your code
|
243
|
-
end
|
244
|
-
|
245
|
-
def click(event)
|
246
|
-
# your code
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
AhoyEmail.subscribers << EmailSubscriber.new
|
293
|
+
AhoyEmail.stats
|
251
294
|
```
|
252
295
|
|
253
|
-
|
296
|
+
Get stats for a specific campaign
|
254
297
|
|
255
298
|
```ruby
|
256
|
-
|
257
|
-
def open(event)
|
258
|
-
event[:controller].ahoy.track "Email opened", message_id: event[:message].id
|
259
|
-
end
|
260
|
-
|
261
|
-
def click(event)
|
262
|
-
event[:controller].ahoy.track "Email clicked", message_id: event[:message].id, url: event[:url]
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
AhoyEmail.subscribers << EmailSubscriber.new
|
299
|
+
AhoyEmail.stats("my-campaign")
|
267
300
|
```
|
268
301
|
|
269
|
-
##
|
270
|
-
|
271
|
-
We recommend encrypting the `to` field (as well as the `subject` if it’s sensitive). [Lockbox](https://github.com/ankane/lockbox) is great for this. Use [Blind Index](https://github.com/ankane/blind_index) if you need to query by the `to` field.
|
302
|
+
## Upgrading
|
272
303
|
|
273
|
-
|
304
|
+
### 2.0
|
274
305
|
|
275
|
-
|
276
|
-
class Ahoy::Message < ApplicationRecord
|
277
|
-
self.table_name = "ahoy_messages"
|
278
|
-
belongs_to :user, polymorphic: true, optional: true
|
306
|
+
Ahoy Email 2.0 brings a number of changes. Here are a few to be aware of:
|
279
307
|
|
280
|
-
|
281
|
-
blind_index :to
|
282
|
-
end
|
283
|
-
```
|
308
|
+
- The `to` field is encrypted by default for new installations. If you’d like to encrypt an existing installation, install [Lockbox](https://github.com/ankane/lockbox) and [Blind Index](https://github.com/ankane/blind_index) and follow the Lockbox instructions for [migrating existing data](https://github.com/ankane/lockbox#migrating-existing-data).
|
284
309
|
|
285
|
-
|
286
|
-
|
287
|
-
Delete older data with:
|
310
|
+
For the model, create `app/models/ahoy/message.rb` with:
|
288
311
|
|
289
|
-
```ruby
|
290
|
-
Ahoy::Message
|
291
|
-
|
292
|
-
|
293
|
-
Delete data for a specific user with:
|
294
|
-
|
295
|
-
```ruby
|
296
|
-
Ahoy::Message.where(user_id: 1).in_batches.delete_all
|
297
|
-
```
|
312
|
+
```ruby
|
313
|
+
class Ahoy::Message < ActiveRecord::Base
|
314
|
+
self.table_name = "ahoy_messages"
|
298
315
|
|
299
|
-
|
316
|
+
belongs_to :user, polymorphic: true, optional: true
|
300
317
|
|
301
|
-
|
318
|
+
encrypts :to, migrating: true
|
319
|
+
blind_index :to, migrating: true
|
320
|
+
end
|
321
|
+
```
|
302
322
|
|
303
|
-
|
304
|
-
AhoyEmail.default_options[:user] = -> { params[:admin] }
|
305
|
-
```
|
323
|
+
- The `track` method has been broken into:
|
306
324
|
|
307
|
-
|
325
|
+
- `has_history` for message history
|
326
|
+
- `utm_params` for UTM tagging
|
327
|
+
- `track_clicks` for click analytics
|
308
328
|
|
309
|
-
|
310
|
-
AhoyEmail.message_model = -> { UserMessage }
|
311
|
-
```
|
329
|
+
- Message history is no longer enabled by default. Add `has_history` to individual mailers, or create an initializer with:
|
312
330
|
|
313
|
-
|
331
|
+
```ruby
|
332
|
+
AhoyEmail.default_options[:message] = true
|
333
|
+
```
|
314
334
|
|
315
|
-
|
316
|
-
AhoyEmail.track_method = lambda do |data|
|
317
|
-
# your code
|
318
|
-
end
|
319
|
-
```
|
335
|
+
- For privacy, open tracking has been removed.
|
320
336
|
|
321
|
-
|
337
|
+
- For clicks, we encourage you to try [aggregate analytics](#click-analytics) to measure the performance of campaigns. You can use a library like [Rollup](https://github.com/ankane/rollup) to aggregate existing data, then drop the `token` and `clicked_at` columns.
|
322
338
|
|
323
|
-
|
339
|
+
To keep individual analytics, use `has_history` and `track_clicks campaign: false` and create an initializer with:
|
324
340
|
|
325
|
-
```ruby
|
326
|
-
|
327
|
-
|
341
|
+
```ruby
|
342
|
+
AhoyEmail.save_token = true
|
343
|
+
AhoyEmail.subscribers << AhoyEmail::MessageSubscriber
|
344
|
+
```
|
328
345
|
|
329
|
-
|
346
|
+
If you use a custom subscriber, `:message` is no longer included in click events. You can use `:token` to query the message if needed.
|
330
347
|
|
331
|
-
|
332
|
-
field :mailer, type: String
|
333
|
-
field :subject, type: String
|
334
|
-
field :sent_at, type: Time
|
335
|
-
end
|
336
|
-
```
|
348
|
+
- Users are shown a link expired page when signature verification fails instead of being redirected to the homepage when `AhoyEmail.invalid_redirect_url` is not set
|
337
349
|
|
338
350
|
## History
|
339
351
|
|