heya 0.9.0 → 0.11.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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +264 -86
- data/app/mailers/heya/campaign_mailer.rb +5 -0
- data/app/models/heya/campaign_membership.rb +3 -12
- data/lib/generators/heya/campaign/templates/message.html.erb.tt +1 -1
- data/lib/generators/heya/campaign/templates/message.md.erb.tt +1 -1
- data/lib/generators/heya/campaign/templates/message.text.erb.tt +1 -1
- data/lib/heya/active_record_extension.rb +2 -2
- data/lib/heya/engine.rb +12 -0
- data/lib/heya/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8c3a56453c65b17eaa7dcc3489bacd9dcdb78da9f134e18e0fa7d3cc818de11
|
4
|
+
data.tar.gz: cd6eb4a27002ebb62307cd44007960cc39637f7ab6b3129d5800061e1bf762c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69aacf834f7a3d02e63aff2dc4be5af386785e2c5172c19dadedb6789c1557332efbbc33db3a2be75382a05f0b746c7c1787fd369bbbc081e655c137006905df
|
7
|
+
data.tar.gz: 2d3c1465261ba7b1737aa64e20b00e14f696f401f1abe1a93e31ec3fd6b5133d7f4fc6cee886a817e478a43ca3ae4ec5ba9760a4e62a685f6db9568acddab0b9
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
|
+
### Added
|
9
|
+
- Support Rails 7.2 (#270, @jbennett)
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
- Fix a typo in message.html.erb.tt.
|
13
|
+
|
14
|
+
## [0.10.0] - 2024-03-18
|
15
|
+
### Added
|
16
|
+
- Add lambda support for from, bcc, and reply_to campaign options (#233, @armiiller)
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
- Fix a Rails startup bug when validating steps that use translations from locale
|
20
|
+
files. (#211)
|
21
|
+
|
22
|
+
## [0.9.0] - 2023-10-06
|
23
|
+
### Added
|
8
24
|
- Rails 7.1 support
|
9
25
|
|
10
26
|
## [0.8.0] - 2023-03-28
|
data/README.md
CHANGED
@@ -1,72 +1,89 @@
|
|
1
1
|
# Heya 👋
|
2
|
+
|
2
3
|

|
3
4
|
[](https://badge.fury.io/rb/heya)
|
4
5
|
[](https://codeclimate.com/github/honeybadger-io/heya/maintainability)
|
5
6
|
|
6
|
-
Heya is a campaign mailer for Rails. Think of it like ActionMailer, but for
|
7
|
+
Heya is a campaign mailer for Rails. Think of it like ActionMailer, but for
|
8
|
+
timed email sequences. It can also perform other actions like sending a text
|
9
|
+
message.
|
7
10
|
|
8
11
|
## Getting started
|
12
|
+
|
9
13
|
Getting started with Heya is easy:
|
10
14
|
|
11
15
|
1. [Install the gem](#installing-the-heya-gem)
|
12
16
|
2. [Create a campaign](#creating-your-first-campaign)
|
13
17
|
3. [Run the scheduler](#running-the-scheduler)
|
14
18
|
|
19
|
+
### Prerequisites
|
20
|
+
|
21
|
+
Heya was built to work with PostgreSQL. Pull requests are welcome to support
|
22
|
+
more databases.
|
23
|
+
|
15
24
|
### Installing the Heya gem
|
25
|
+
|
16
26
|
1. Add this line to your application's Gemfile:
|
17
27
|
|
18
|
-
|
19
|
-
|
20
|
-
|
28
|
+
```ruby
|
29
|
+
gem "heya", github: "honeybadger-io/heya"
|
30
|
+
```
|
21
31
|
|
22
32
|
2. Then execute:
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
34
|
+
```bash
|
35
|
+
bundle install
|
36
|
+
rails generate heya:install
|
37
|
+
rails db:migrate
|
38
|
+
```
|
29
39
|
|
30
|
-
|
40
|
+
This will:
|
31
41
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
42
|
+
1. Copy Heya's migration files to _db/migrate_
|
43
|
+
1. Copy Heya's default initializer to _config/initializers/heya.rb_
|
44
|
+
1. Create the file _app/campaigns/application_campaign.rb_
|
45
|
+
1. Run local migrations
|
36
46
|
|
37
|
-
<details
|
47
|
+
<details>
|
48
|
+
<summary>Note: Heya doesn't store a copy of your user data; instead, it
|
49
|
+
reads from your existing <code>User</code> model (it never writes). If you
|
50
|
+
have a different user model, change the <code>user_type</code> configuration
|
51
|
+
option in <em>config/initializers/heya.rb</em>.</summary>
|
38
52
|
|
39
53
|
```ruby
|
40
54
|
# config/initializers/heya.rb
|
41
55
|
Heya.configure do |config|
|
42
|
-
|
56
|
+
config.user_type = "MyUser"
|
43
57
|
end
|
44
58
|
```
|
59
|
+
|
45
60
|
</details>
|
46
61
|
|
47
62
|
### Creating your first campaign
|
63
|
+
|
48
64
|
1. Create a campaign:
|
49
65
|
|
50
|
-
|
51
|
-
|
52
|
-
|
66
|
+
```bash
|
67
|
+
rails generate heya:campaign Onboarding welcome:0
|
68
|
+
```
|
53
69
|
|
54
70
|
2. Add a user to your campaign:
|
55
71
|
|
56
|
-
|
57
|
-
|
58
|
-
|
72
|
+
```ruby
|
73
|
+
OnboardingCampaign.add(user)
|
74
|
+
```
|
59
75
|
|
60
|
-
|
61
|
-
|
76
|
+
Add the following to your `User` model to send them the campaign
|
77
|
+
when they first sign up:
|
62
78
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
79
|
+
```ruby
|
80
|
+
after_create_commit do
|
81
|
+
OnboardingCampaign.add(self)
|
82
|
+
end
|
83
|
+
```
|
68
84
|
|
69
85
|
### Running the scheduler
|
86
|
+
|
70
87
|
To start queuing emails, run the scheduler task periodically:
|
71
88
|
|
72
89
|
```bash
|
@@ -92,7 +109,9 @@ end
|
|
92
109
|
|
93
110
|
### Bonus: tips for working with email in Rails
|
94
111
|
|
95
|
-
<details
|
112
|
+
<details>
|
113
|
+
<summary>Use <a href="http://mailcatcher.me">MailCatcher</a> to see
|
114
|
+
emails sent from your dev environment</summary>
|
96
115
|
|
97
116
|
```ruby
|
98
117
|
# config/environments/development.rb
|
@@ -111,8 +130,11 @@ Rails.application.configure do
|
|
111
130
|
config.action_mailer.smtp_settings = {host: "localhost", port: 1025}
|
112
131
|
end
|
113
132
|
```
|
133
|
+
|
114
134
|
</details>
|
115
|
-
<details
|
135
|
+
<details>
|
136
|
+
<summary>Use <a href="https://github.com/codetriage/maildown">Maildown</a> to
|
137
|
+
write your emails in Markdown</summary>
|
116
138
|
|
117
139
|
```sh
|
118
140
|
$ bundle add maildown
|
@@ -124,12 +146,16 @@ $ rails generate heya:campaign Onboarding welcome
|
|
124
146
|
|
125
147
|
☝️ Notice how only one template was generated; Maildown automatically builds
|
126
148
|
the HTML and text variants from the markdown file.
|
149
|
+
|
127
150
|
</details>
|
128
|
-
<details
|
151
|
+
<details>
|
152
|
+
<summary>Use <a
|
153
|
+
href="https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails">ActionMailer::Preview</a>
|
154
|
+
to preview emails as you write them</summary>
|
129
155
|
|
130
156
|
Heya's campaign generator generates previews for campaigns at
|
131
157
|
`(test|spec)/mailers/previews/*_campaign_preview.rb`. To see them, open
|
132
|
-
http://localhost:3000/rails/mailers
|
158
|
+
<http://localhost:3000/rails/mailers/>. If you didn't use the generator, you
|
133
159
|
can still build your own preview:
|
134
160
|
|
135
161
|
```ruby
|
@@ -147,12 +173,13 @@ class OnboardingCampaignPreview < ActionMailer::Preview
|
|
147
173
|
end
|
148
174
|
|
149
175
|
```
|
176
|
+
|
150
177
|
</details>
|
151
178
|
|
152
179
|
## Configuration
|
153
180
|
|
154
181
|
You can use the following options to configure Heya (find this file in
|
155
|
-
|
182
|
+
_config/initializers/heya.rb_):
|
156
183
|
|
157
184
|
```ruby
|
158
185
|
Heya.configure do |config|
|
@@ -176,7 +203,10 @@ end
|
|
176
203
|
## Campaigns
|
177
204
|
|
178
205
|
### Creating campaigns
|
179
|
-
|
206
|
+
|
207
|
+
Heya stores campaigns in _app/campaigns/_, similar to how Rails stores mailers
|
208
|
+
in _app/mailers/_. To create a campaign, run the following command inside your
|
209
|
+
Rails project:
|
180
210
|
|
181
211
|
```bash
|
182
212
|
rails generate heya:campaign Onboarding first second third
|
@@ -184,10 +214,10 @@ rails generate heya:campaign Onboarding first second third
|
|
184
214
|
|
185
215
|
This will:
|
186
216
|
|
187
|
-
1. Create the file
|
188
|
-
1. Create the directory
|
189
|
-
1. Create email templates inside of
|
190
|
-
1. Create an ActionMailer preview at
|
217
|
+
1. Create the file _app/campaigns/onboarding_campaign.rb_
|
218
|
+
1. Create the directory _app/views/heya/campaign_mailer/onboarding_campaign/_
|
219
|
+
1. Create email templates inside of _app/views/heya/campaign_mailer/onboarding_campaign/_
|
220
|
+
1. Create an ActionMailer preview at _(test|spec)/mailers/previews/onboarding_campaign_preview.rb_
|
191
221
|
|
192
222
|
Here's the campaign that the above command generates:
|
193
223
|
|
@@ -211,16 +241,26 @@ end
|
|
211
241
|
```
|
212
242
|
|
213
243
|
#### Steps
|
214
|
-
The `step` method defines a new step in the sequence. When you add a user to the campaign, Heya completes each step in the order that it appears.
|
215
244
|
|
216
|
-
The
|
245
|
+
The `step` method defines a new step in the sequence. When you add a user to the
|
246
|
+
campaign, Heya completes each step in the order that it appears.
|
247
|
+
|
248
|
+
The default time to wait between steps is _two days_, calculated from the time
|
249
|
+
the user completed the previous step (or the time the user entered the campaign,
|
250
|
+
in the case of the first step).
|
217
251
|
|
218
|
-
Each step has several options available (see the section [Creating
|
252
|
+
Each step has several options available (see the section [Creating
|
253
|
+
messages](#creating-messages)).
|
219
254
|
|
220
255
|
### Creating messages
|
221
|
-
Messages are defined inside Heya campaigns using the `step` method. When you add a user to a campaign, Heya completes each step in the order that it appears.
|
222
256
|
|
223
|
-
|
257
|
+
Messages are defined inside Heya campaigns using the `step` method. When you add
|
258
|
+
a user to a campaign, Heya completes each step in the order that it appears.
|
259
|
+
|
260
|
+
**The most important part of each step is its name, which must be unique to the
|
261
|
+
campaign.** The step's name is how Heya tracks which user has received which
|
262
|
+
message, so it's essential that you don't change it after the campaign is active
|
263
|
+
(if you do, Heya will assume it's a new message).
|
224
264
|
|
225
265
|
Here's an example of defining a message inside a campaign:
|
226
266
|
|
@@ -231,9 +271,12 @@ class OnboardingCampaign < ApplicationCampaign
|
|
231
271
|
end
|
232
272
|
```
|
233
273
|
|
234
|
-
In the above example, Heya will send a message named `:welcome` one day after a
|
274
|
+
In the above example, Heya will send a message named `:welcome` one day after a
|
275
|
+
user enters the campaign, with the subject "Welcome to my app!"
|
235
276
|
|
236
|
-
The `wait` option tells Heya how long to wait before sending each message (the
|
277
|
+
The `wait` option tells Heya how long to wait before sending each message (the
|
278
|
+
default is two days). There are a few scheduling options that you can customize
|
279
|
+
for each step:
|
237
280
|
|
238
281
|
| Option Name | Default | Description |
|
239
282
|
| :---------- | :-------------------------------- | :------------------------------------------------------- |
|
@@ -244,16 +287,18 @@ The `wait` option tells Heya how long to wait before sending each message (the d
|
|
244
287
|
|
245
288
|
Heya uses the following additional options to build the message itself:
|
246
289
|
|
247
|
-
| Option Name | Default | Description
|
248
|
-
|
249
|
-
| `subject` | **required** | The email's subject
|
250
|
-
| `from` | Heya default | The sender's email address
|
251
|
-
| `layout` | Heya default | The email's layout file
|
252
|
-
| `to` | See below | The recipient's name & email address
|
253
|
-
| `bcc` | `nil` | BCC when sending emails
|
290
|
+
| Option Name | Default | Description |
|
291
|
+
| ----------- | ------------ | -------------------------------------- |
|
292
|
+
| `subject` | **required** | The email's subject |
|
293
|
+
| `from` | Heya default | The sender's email address |
|
294
|
+
| `layout` | Heya default | The email's layout file |
|
295
|
+
| `to` | See below | The recipient's name & email address |
|
296
|
+
| `bcc` | `nil` | BCC when sending emails |
|
254
297
|
| `headers` | `{}` | Headers to include when sending emails |
|
255
298
|
|
256
|
-
You can change the default options using the `default` method at the top of the
|
299
|
+
You can change the default options using the `default` method at the top of the
|
300
|
+
campaign. Heya applies default options to each step which doesn't supply its
|
301
|
+
own:
|
257
302
|
|
258
303
|
```ruby
|
259
304
|
class OnboardingCampaign < ApplicationCampaign
|
@@ -271,7 +316,8 @@ end
|
|
271
316
|
|
272
317
|
#### Customizing the `to` field
|
273
318
|
|
274
|
-
You can customize the `to` field by passing a callable object, which Heya will
|
319
|
+
You can customize the `to` field by passing a callable object, which Heya will
|
320
|
+
invoke with the user. For instance:
|
275
321
|
|
276
322
|
```ruby
|
277
323
|
class OnboardingCampaign < ApplicationCampaign
|
@@ -281,19 +327,23 @@ class OnboardingCampaign < ApplicationCampaign
|
|
281
327
|
end
|
282
328
|
```
|
283
329
|
|
284
|
-
It is recommended to rely on `ActionMailer::Base.email_address_with_name` so
|
330
|
+
It is recommended to rely on `ActionMailer::Base.email_address_with_name` so
|
331
|
+
that sanitization is correctly applied.
|
285
332
|
|
286
333
|
If the `to` param is not provided, Heya will default to:
|
287
334
|
|
288
335
|
1. `user#first_name`
|
289
336
|
1. `user#name`
|
290
337
|
|
291
|
-
If the `user` object doesn't respond to these methods, it will fallback to a
|
338
|
+
If the `user` object doesn't respond to these methods, it will fallback to a
|
339
|
+
simple `user.email` in the `to` field.
|
292
340
|
|
293
341
|
#### Quality control option
|
294
342
|
|
295
|
-
You may wish to apply quality control to individual steps of a campaign. For
|
296
|
-
|
343
|
+
You may wish to apply quality control to individual steps of a campaign. For
|
344
|
+
example, when adding a new step to an existing campaign it is a good idea to
|
345
|
+
inspect real-time results in production. You can do this by using the `bcc:`
|
346
|
+
step option, which would look like this:
|
297
347
|
|
298
348
|
```ruby
|
299
349
|
class OnboardingCampaign < ApplicationCampaign
|
@@ -326,7 +376,9 @@ end
|
|
326
376
|
|
327
377
|
#### Translations for email subjects (I18n)
|
328
378
|
|
329
|
-
If you don't pass a `subject` to the `step` method, Heya will try to find it in
|
379
|
+
If you don't pass a `subject` to the `step` method, Heya will try to find it in
|
380
|
+
your translations. The performed lookup will use the pattern
|
381
|
+
`<campaign_scope>.<step_name>.subject` to construct the key.
|
330
382
|
|
331
383
|
```ruby
|
332
384
|
# app/campaigns/onboarding_campaign.rb
|
@@ -343,7 +395,8 @@ en:
|
|
343
395
|
subject: "Heya!"
|
344
396
|
```
|
345
397
|
|
346
|
-
To define parameters for interpolation, define a `#heya_attributes` method on
|
398
|
+
To define parameters for interpolation, define a `#heya_attributes` method on
|
399
|
+
your user model:
|
347
400
|
|
348
401
|
```ruby
|
349
402
|
# app/models/user.rb
|
@@ -387,7 +440,9 @@ Step blocks receive two optional arguments: `user` and `step`, and are processed
|
|
387
440
|
in a background job alongside other actions.
|
388
441
|
|
389
442
|
### Adding users to campaigns
|
390
|
-
|
443
|
+
|
444
|
+
Heya leaves _when_ to add users to campaigns completely up to you; here's how to
|
445
|
+
add a user to a campaign from anywhere in your app:
|
391
446
|
|
392
447
|
```ruby
|
393
448
|
OnboardingCampaign.add(user)
|
@@ -399,24 +454,33 @@ To remove a user from a campaign:
|
|
399
454
|
OnboardingCampaign.remove(user)
|
400
455
|
```
|
401
456
|
|
402
|
-
Adding users to campaigns from Rails opens up some interesting automation
|
457
|
+
Adding users to campaigns from Rails opens up some interesting automation
|
458
|
+
possibilities--for instance, you can start or stop campaigns from `ActiveRecord`
|
459
|
+
callbacks, or in response to other events that you're already tracking in your
|
460
|
+
application. [See here for a list of ideas](#automation-ideas).
|
403
461
|
|
404
|
-
Because Heya stacks campaigns by default (meaning it will never send more than
|
462
|
+
Because Heya stacks campaigns by default (meaning it will never send more than
|
463
|
+
one at a time), you can also queue up several campaigns for a user, and they'll
|
464
|
+
receive them in order:
|
405
465
|
|
406
466
|
```ruby
|
407
467
|
WelcomeCampaign.add(user)
|
408
468
|
OnboardingCampaign.add(user)
|
409
469
|
EvergreenCampaign.add(user)
|
410
470
|
```
|
411
|
-
*Note: you can customize the priority of campaigns via Heya's configuration.*
|
412
471
|
|
413
|
-
|
472
|
+
_Note: you can customize the priority of campaigns via Heya's configuration._
|
473
|
+
|
474
|
+
If you want to send a user two campaigns simultaneously, you can do so with the
|
475
|
+
`concurrent` option:
|
414
476
|
|
415
477
|
```ruby
|
416
478
|
FlashSaleCampaign.add(user, concurrent: true)
|
417
479
|
```
|
418
480
|
|
419
|
-
When you remove a user from a campaign and add them back later, they'll continue
|
481
|
+
When you remove a user from a campaign and add them back later, they'll continue
|
482
|
+
where they left off. If you want them to start over from the beginning, use the
|
483
|
+
`restart` option:
|
420
484
|
|
421
485
|
```ruby
|
422
486
|
TrialConversionCampaign.add(user, restart: true)
|
@@ -424,7 +488,8 @@ TrialConversionCampaign.add(user, restart: true)
|
|
424
488
|
|
425
489
|
#### Automation ideas
|
426
490
|
|
427
|
-
Using `ActiveSupport::Notifications` to respond to lifecycle events (which could
|
491
|
+
Using `ActiveSupport::Notifications` to respond to lifecycle events (which could
|
492
|
+
be sent from your Stripe controller, for instance):
|
428
493
|
|
429
494
|
```ruby
|
430
495
|
ActiveSupport::Notifications.subscribe("user.trial_will_end") do |*args|
|
@@ -449,7 +514,10 @@ end
|
|
449
514
|
```
|
450
515
|
|
451
516
|
### Customizing who gets what
|
452
|
-
|
517
|
+
|
518
|
+
Heya can send individual messages to certain users using the `segment` option.
|
519
|
+
The following campaign will send the message to inactive users--active users
|
520
|
+
will be skipped:
|
453
521
|
|
454
522
|
```ruby
|
455
523
|
class ActivationCampaign < ApplicationCampaign
|
@@ -457,7 +525,8 @@ class ActivationCampaign < ApplicationCampaign
|
|
457
525
|
end
|
458
526
|
```
|
459
527
|
|
460
|
-
When you're checking the value of a single method on the user, the segment can
|
528
|
+
When you're checking the value of a single method on the user, the segment can
|
529
|
+
be simplified to the symbol version:
|
461
530
|
|
462
531
|
```ruby
|
463
532
|
class ActivationCampaign < ApplicationCampaign
|
@@ -466,7 +535,11 @@ end
|
|
466
535
|
```
|
467
536
|
|
468
537
|
#### Segmenting specific campaigns
|
469
|
-
|
538
|
+
|
539
|
+
You can also narrow entire campaigns to certain users using the `segment`
|
540
|
+
method. For instance, if you have a campaign with a specific goal such as
|
541
|
+
performing an action in your app, then you can send the campaign only to the
|
542
|
+
users who haven't performed the action:
|
470
543
|
|
471
544
|
```ruby
|
472
545
|
class UpgradeCampaign < ApplicationCampaign
|
@@ -478,9 +551,12 @@ class UpgradeCampaign < ApplicationCampaign
|
|
478
551
|
end
|
479
552
|
```
|
480
553
|
|
481
|
-
If they upgrade half way through the campaign, Heya will stop sending messages
|
554
|
+
If they upgrade half way through the campaign, Heya will stop sending messages
|
555
|
+
and remove them from the campaign.
|
482
556
|
|
483
|
-
Likewise, you can require that users meet conditions to continue receiving a
|
557
|
+
Likewise, you can require that users meet conditions to continue receiving a
|
558
|
+
campaign. Here's a campaign which sends messages only to trial users--non-trial
|
559
|
+
users will be removed from the campaign:
|
484
560
|
|
485
561
|
```ruby
|
486
562
|
class TrialCampaign < ApplicationCampaign
|
@@ -493,6 +569,7 @@ end
|
|
493
569
|
```
|
494
570
|
|
495
571
|
#### Segmenting all campaigns
|
572
|
+
|
496
573
|
Heya campaigns inherit options from parent campaigns. For example, to make sure
|
497
574
|
unsubscribed users never receive an email from Heya, create a `segment` in the
|
498
575
|
`ApplicationCampaign`, and then have all other campaigns inherit from it:
|
@@ -524,72 +601,169 @@ See the
|
|
524
601
|
[Rails documentation](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html#method-i-rescue_from)
|
525
602
|
for additional details.
|
526
603
|
|
604
|
+
### Extending campaign mailers
|
605
|
+
|
606
|
+
The campaign generator does not create a Mailer class for campaigns. In order to
|
607
|
+
enhance a campaign with a macro from another gem (such as for adding analytics),
|
608
|
+
you can do so by extending the `Heya::ApplicationMailer` class.
|
609
|
+
|
610
|
+
1. Create a new file at `app/mailers/heya/application_mailer.rb`
|
611
|
+
2. Add the following to it:
|
612
|
+
|
613
|
+
```ruby
|
614
|
+
module Heya
|
615
|
+
class ApplicationMailer < ActionMailer::Base
|
616
|
+
macro_to_add_to_all_campaign_mailers
|
617
|
+
end
|
618
|
+
end
|
619
|
+
```
|
620
|
+
|
621
|
+
For example, here's how to extended `Heya::ApplicationMailer` to include [Ahoy
|
622
|
+
Email's](https://github.com/ankane/ahoy_email)
|
623
|
+
[has_history](https://github.com/ankane/ahoy_email?tab=readme-ov-file#message-history)
|
624
|
+
and
|
625
|
+
[track_clicks](https://github.com/ankane/ahoy_email?tab=readme-ov-file#usage)
|
626
|
+
macros:
|
627
|
+
|
628
|
+
```ruby
|
629
|
+
# app/mailers/heya/application_mailer.rb
|
630
|
+
|
631
|
+
module Heya
|
632
|
+
class ApplicationMailer < ActionMailer::Base
|
633
|
+
has_history
|
634
|
+
|
635
|
+
track_clicks campaign: -> {
|
636
|
+
params[:step].campaign.name
|
637
|
+
}
|
638
|
+
end
|
639
|
+
end
|
640
|
+
```
|
641
|
+
|
642
|
+
This does two things:
|
643
|
+
|
644
|
+
1. `has_history` enables history tracking for all Heya emails
|
645
|
+
2. The `track_clicks` block appends the name of the campaign to all
|
646
|
+
(non-unsubscribe) links in an email so that each campaign can keep its data
|
647
|
+
separate from the other campaigns.
|
648
|
+
|
649
|
+
The result of this is that you can run a command like this in the console:
|
650
|
+
|
651
|
+
```irb
|
652
|
+
AhoyEmail.stats "OnboardingCampaign"
|
653
|
+
```
|
654
|
+
|
655
|
+
...and receive a result:
|
656
|
+
|
657
|
+
```irb
|
658
|
+
=> {:sends=>1, :clicks=>2, :unique_clicks=>1, :ctr=>100.0}
|
659
|
+
```
|
660
|
+
|
527
661
|
### Campaigns FAQ
|
662
|
+
|
528
663
|
**What happens when:**
|
664
|
+
|
529
665
|
<details><summary>I reorder messages in an active campaign?</summary>
|
530
666
|
|
531
|
-
Heya sends the next
|
667
|
+
Heya sends the next _unsent_ message _after the last message the user received_.
|
668
|
+
When you move a message, the users who last received it will be moved with it,
|
669
|
+
and continue from that point in the campaign. Heya skips messages which the user
|
670
|
+
has already seen.
|
671
|
+
|
532
672
|
</details>
|
533
673
|
|
534
674
|
<details><summary>I add a message to an active campaign?</summary>
|
535
675
|
|
536
|
-
Users who have already received a message
|
676
|
+
Users who have already received a message _after_ the new message will _not_
|
677
|
+
receive the message.
|
678
|
+
|
537
679
|
</details>
|
538
680
|
|
539
681
|
<details><summary>I remove a message from an active campaign?</summary>
|
540
682
|
|
541
|
-
Users who last received the message will be moved up to the previously received
|
683
|
+
Users who last received the message will be moved up to the previously received
|
684
|
+
message, and continue from that point in the campaign. Heya skips messages which
|
685
|
+
the user has already seen.
|
686
|
+
|
542
687
|
</details>
|
543
688
|
|
544
689
|
<details><summary>I rename a message in an active campaign?</summary>
|
545
690
|
|
546
|
-
**Renaming a message is equivalent to removing the message and adding a new
|
691
|
+
**Renaming a message is equivalent to removing the message and adding a new
|
692
|
+
one.** Users who are waiting to receive an earlier message in the campaign will
|
693
|
+
receive the new message. Users who last received the old message will also
|
694
|
+
receive the new one since it has replaced its position in the campaign.
|
695
|
+
|
547
696
|
</details>
|
548
697
|
|
549
698
|
<details><summary>A user skips a message based on its conditions?</summary>
|
550
699
|
|
551
|
-
Heya waits the defined wait time for every message in the campaign. If a user
|
700
|
+
Heya waits the defined wait time for every message in the campaign. If a user
|
701
|
+
doesn't match the conditions, Heya skips it. If the _next_ message's wait time
|
702
|
+
is less than or equal to the skipped message's, it sends it immediately. If the
|
703
|
+
next wait period is longer, it sends it after the new wait time has elapsed.
|
704
|
+
|
552
705
|
</details>
|
553
706
|
|
554
707
|
<details><summary>I delete an active campaign?</summary>
|
555
708
|
|
556
|
-
Heya will immediately stop sending the campaign; the campaign's data will remain
|
709
|
+
Heya will immediately stop sending the campaign; the campaign's data will remain
|
710
|
+
until you manually delete it. If you restore the file before deleting the
|
711
|
+
campaign's data, Heya will resume sending the campaign.
|
712
|
+
|
557
713
|
</details>
|
558
714
|
|
559
715
|
<details><summary>I add a user to multiple campaigns?</summary>
|
560
716
|
|
561
|
-
By default, Heya sends each user one campaign at a time. It determines the order
|
717
|
+
By default, Heya sends each user one campaign at a time. It determines the order
|
718
|
+
of campaigns using the campaign `priority`. When you add a user to a higher
|
719
|
+
priority campaign, the new campaign will begin immediately. Once completed, the
|
720
|
+
next highest priority campaign will resume sending.
|
562
721
|
|
563
722
|
To send a campaign concurrent to other active campaigns, use the `concurrent` option.
|
723
|
+
|
564
724
|
</details>
|
565
725
|
|
566
726
|
<details><summary>I add a user to a campaign they already completed?</summary>
|
567
727
|
|
568
|
-
When you add a user to a campaign that they previously completed, Heya sends new
|
728
|
+
When you add a user to a campaign that they previously completed, Heya sends new
|
729
|
+
messages which were added _to the end of the campaign_. Skipped messages will
|
730
|
+
_not_ be sent. To resend all messages, use the `restart` option.
|
731
|
+
|
569
732
|
</details>
|
570
733
|
|
571
734
|
**Less frequently asked questions:**
|
735
|
+
|
572
736
|
<details><summary>Can the same message be delivered twice?</summary>
|
573
737
|
|
574
|
-
Nope, not without restarting the campaign using the `restart` option (which will
|
738
|
+
Nope, not without restarting the campaign using the `restart` option (which will
|
739
|
+
resend all the messages).
|
740
|
+
|
575
741
|
</details>
|
576
742
|
|
577
743
|
<details><summary>Can the same campaign be sent twice?</summary>
|
578
744
|
|
579
|
-
Yep. When you add a user to a campaign that they previously completed, Heya
|
745
|
+
Yep. When you add a user to a campaign that they previously completed, Heya
|
746
|
+
sends new messages which were added _to the end of the campaign_. Skipped
|
747
|
+
messages will _not_ be sent. To resend all messages, use the `restart` option.
|
748
|
+
|
580
749
|
</details>
|
581
750
|
|
582
751
|
<details><summary>Can I resend a campaign to a user?</summary>
|
583
752
|
|
584
|
-
Yep. Use the `restart` option to resend a campaign to a user (if they are
|
753
|
+
Yep. Use the `restart` option to resend a campaign to a user (if they are
|
754
|
+
already in the campaign, the campaign will start over from the beginning).
|
755
|
+
|
585
756
|
</details>
|
586
757
|
|
587
758
|
<details><summary>Can I send a user two campaigns at the same time?</summary>
|
588
759
|
|
589
|
-
Yep. By default, Heya sends campaigns ain order of `priority`. Use the
|
760
|
+
Yep. By default, Heya sends campaigns ain order of `priority`. Use the
|
761
|
+
`concurrent` option to send campaigns concurrently.
|
762
|
+
|
590
763
|
</details>
|
591
764
|
|
592
765
|
## Upgrading Heya
|
766
|
+
|
593
767
|
Heya adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and
|
594
768
|
should be considered **unstable** until version 1.0.0. Always check
|
595
769
|
[CHANGELOG.md](./CHANGELOG.md) prior to upgrading (breaking changes will always
|
@@ -597,18 +771,21 @@ be called out there). Upgrade instructions for breaking changes are in
|
|
597
771
|
[UPGRADING.md](./UPGRADING.md).
|
598
772
|
|
599
773
|
## Roadmap
|
774
|
+
|
600
775
|
See [here](https://github.com/honeybadger-io/heya/projects/1) for things we're
|
601
776
|
considering adding to Heya.
|
602
777
|
|
603
778
|
## Contributing
|
779
|
+
|
604
780
|
1. Fork it.
|
605
781
|
2. Create a topic branch `git checkout -b my_branch`
|
606
|
-
3. Make your changes and add an entry to [CHANGELOG.md](CHANGELOG.md).
|
782
|
+
3. Make your changes and add an entry to [CHANGELOG.md](./CHANGELOG.md).
|
607
783
|
4. Commit your changes `git commit -am "Boom"`
|
608
784
|
5. Push to your branch `git push origin my_branch`
|
609
785
|
6. Send a [pull request](https://github.com/honeybadger-io/heya/pulls)
|
610
786
|
|
611
787
|
## Releasing
|
788
|
+
|
612
789
|
1. `gem install gem-release`
|
613
790
|
2. `gem bump -v [version] -t -r`
|
614
791
|
3. Update unreleased heading in [CHANGELOG.md](./CHANGELOG.md) (TODO: automate
|
@@ -616,4 +793,5 @@ considering adding to Heya.
|
|
616
793
|
4. `git push origin main --tags`
|
617
794
|
|
618
795
|
## License
|
796
|
+
|
619
797
|
Heya is licensed under the [LGPL](./LICENSE).
|
@@ -12,8 +12,13 @@ module Heya
|
|
12
12
|
step_name = step.name.underscore
|
13
13
|
|
14
14
|
from = step.params.fetch("from")
|
15
|
+
from = from.call(user) if from.respond_to?(:call)
|
16
|
+
|
15
17
|
bcc = step.params.fetch("bcc", nil)
|
18
|
+
bcc = bcc.call(user) if bcc.respond_to?(:call)
|
19
|
+
|
16
20
|
reply_to = step.params.fetch("reply_to", nil)
|
21
|
+
reply_to = reply_to.call(user) if reply_to.respond_to?(:call)
|
17
22
|
|
18
23
|
subject = step.params.fetch("subject") {
|
19
24
|
I18n.t("#{campaign_name}.#{step_name}.subject", **attributes_for(user))
|
@@ -50,18 +50,9 @@ module Heya
|
|
50
50
|
}
|
51
51
|
|
52
52
|
scope :to_process, ->(now: Time.now, user: nil) {
|
53
|
-
upcoming
|
54
|
-
|
55
|
-
|
56
|
-
AND (
|
57
|
-
(:user_type IS NULL OR :user_id IS NULL)
|
58
|
-
OR (
|
59
|
-
"heya_campaign_memberships".user_type = :user_type
|
60
|
-
AND
|
61
|
-
"heya_campaign_memberships".user_id = :user_id
|
62
|
-
)
|
63
|
-
)
|
64
|
-
SQL
|
53
|
+
query = upcoming.where('heya_campaign_memberships.last_sent_at <= (:now::timestamp - make_interval(secs := "heya_steps".wait))', now: now.utc)
|
54
|
+
query = query.where(user: user) if user
|
55
|
+
query
|
65
56
|
}
|
66
57
|
|
67
58
|
def self.migrate_next_step!
|
@@ -1 +1 @@
|
|
1
|
-
This is the <%= @step.downcase %>
|
1
|
+
This is the <%= @step.downcase %> message.
|
@@ -1 +1 @@
|
|
1
|
-
This is the <%= @step.downcase %>
|
1
|
+
This is the <%= @step.downcase %> message.
|
@@ -1 +1 @@
|
|
1
|
-
This is the <%= @step.downcase %>
|
1
|
+
This is the <%= @step.downcase %> message.
|
@@ -6,8 +6,8 @@ module Heya
|
|
6
6
|
module ActiveRecordRelationExtension
|
7
7
|
TABLE_REGEXP = /heya_steps/
|
8
8
|
|
9
|
-
def build_arel(
|
10
|
-
arel = super(
|
9
|
+
def build_arel(...) # forward all params. Handles differences between 7.1 -> 7.2
|
10
|
+
arel = super(...)
|
11
11
|
|
12
12
|
if table_name == "heya_campaign_memberships" && arel.to_sql =~ TABLE_REGEXP
|
13
13
|
# https://www.postgresql.org/docs/9.4/queries-values.html
|
data/lib/heya/engine.rb
CHANGED
@@ -11,6 +11,18 @@ module Heya
|
|
11
11
|
end
|
12
12
|
|
13
13
|
config.to_prepare do
|
14
|
+
# This runs the first time *before* Rails is initialized. Because
|
15
|
+
# campaigns depend on Rails initialization, we use the `after_initialize`
|
16
|
+
# hook when Rails first starts up, and then `to_prepare` when reloading
|
17
|
+
# in development. See https://github.com/honeybadger-io/heya/issues/211
|
18
|
+
if ::Rails.application.initialized?
|
19
|
+
Dir.glob(Rails.root + "app/campaigns/*.rb").each do |c|
|
20
|
+
require_dependency(c)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
config.after_initialize do
|
14
26
|
Dir.glob(Rails.root + "app/campaigns/*.rb").each do |c|
|
15
27
|
require_dependency(c)
|
16
28
|
end
|
data/lib/heya/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heya
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Wood
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|