maily_herald 0.0.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +10 -4
- data/.rspec +5 -0
- data/Gemfile +1 -12
- data/Gemfile.lock +129 -82
- data/Guardfile +25 -0
- data/LICENSE +10 -0
- data/README.md +346 -0
- data/Rakefile +5 -0
- data/app/controllers/maily_herald/tokens_controller.rb +11 -0
- data/app/helpers/maily_herald/tokens_helper.rb +17 -0
- data/app/mailers/maily_herald/mailer.rb +91 -0
- data/app/models/maily_herald/dispatch.rb +76 -0
- data/app/models/maily_herald/list.rb +99 -0
- data/app/models/maily_herald/log.rb +67 -0
- data/app/models/maily_herald/mailing.rb +139 -7
- data/app/models/maily_herald/one_time_mailing.rb +26 -0
- data/app/models/maily_herald/periodical_mailing.rb +145 -0
- data/app/models/maily_herald/sequence.rb +169 -2
- data/app/models/maily_herald/sequence_mailing.rb +71 -0
- data/app/models/maily_herald/subscription.rb +67 -0
- data/bin/maily_herald +16 -0
- data/config/database.yml +5 -0
- data/config/locales/en.yml +6 -11
- data/config/routes.rb +10 -0
- data/config/spring.rb +1 -0
- data/db/migrate/20150205120443_create_maily_herald_tables.rb +53 -0
- data/db/migrate_legacy/20130711124555_create_maily_herald_tables.rb +67 -0
- data/db/migrate_legacy/20140612101023_create_lists.rb +33 -0
- data/lib/generators/maily_herald/install_generator.rb +3 -3
- data/lib/generators/templates/README +2 -0
- data/lib/generators/templates/maily_herald.rb +1 -0
- data/lib/maily_herald.rb +345 -23
- data/lib/maily_herald/autonaming.rb +34 -0
- data/lib/maily_herald/capistrano.rb +5 -0
- data/lib/maily_herald/capistrano/tasks.cap +67 -0
- data/lib/maily_herald/capistrano/tasks2.rb +20 -0
- data/lib/maily_herald/cli.rb +293 -0
- data/lib/maily_herald/condition_evaluator.rb +82 -0
- data/lib/maily_herald/config.rb +5 -0
- data/lib/maily_herald/context.rb +223 -77
- data/lib/maily_herald/engine.rb +17 -0
- data/lib/maily_herald/logging.rb +90 -0
- data/lib/maily_herald/manager.rb +53 -0
- data/lib/maily_herald/model_extensions.rb +15 -0
- data/lib/maily_herald/template_renderer.rb +16 -0
- data/lib/maily_herald/utils.rb +78 -5
- data/lib/maily_herald/version.rb +1 -1
- data/maily_herald.gemspec +17 -9
- data/spec/controllers/maily_herald/tokens_controller_spec.rb +81 -0
- data/spec/dummy/Guardfile +35 -0
- data/spec/dummy/app/mailers/test_mailer.rb +11 -0
- data/spec/dummy/app/models/product.rb +2 -0
- data/spec/dummy/app/models/user.rb +4 -0
- data/spec/dummy/app/views/test_mailer/sample_mail.text.erb +1 -0
- data/spec/dummy/bin/rails +10 -0
- data/spec/dummy/bin/rake +7 -0
- data/spec/dummy/bin/rspec +7 -0
- data/spec/dummy/bin/spring +18 -0
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/environments/development.rb +1 -0
- data/spec/dummy/config/environments/test.rb +1 -0
- data/spec/dummy/config/initializers/maily_herald.rb +103 -0
- data/spec/dummy/config/locales/maily_herald.en.yml +28 -0
- data/spec/dummy/db/migrate/20130723074347_create_users.rb +18 -0
- data/spec/dummy/db/schema.rb +82 -0
- data/spec/factories/products.rb +5 -0
- data/spec/factories/users.rb +11 -0
- data/spec/lib/context_spec.rb +41 -0
- data/spec/lib/maily_herald_spec.rb +32 -0
- data/spec/lib/utils_spec.rb +48 -0
- data/spec/mailers/maily_herald/mailer_spec.rb +38 -0
- data/spec/models/maily_herald/list_spec.rb +64 -0
- data/spec/models/maily_herald/log_spec.rb +36 -0
- data/spec/models/maily_herald/mailing_spec.rb +34 -0
- data/spec/models/maily_herald/one_time_mailing_spec.rb +112 -0
- data/spec/models/maily_herald/periodical_mailing_spec.rb +339 -0
- data/spec/models/maily_herald/sequence_mailing_spec.rb +18 -0
- data/spec/models/maily_herald/sequence_spec.rb +429 -0
- data/spec/models/maily_herald/subscription_spec.rb +32 -0
- data/spec/spec_helper.rb +31 -11
- metadata +199 -54
- data/MIT-LICENSE +0 -20
- data/README.rdoc +0 -3
- data/app/assets/images/maily_herald/.gitkeep +0 -0
- data/app/assets/javascripts/maily_herald/application.js +0 -15
- data/app/assets/stylesheets/maily_herald/application.css +0 -13
- data/app/helpers/maily_herald/application_helper.rb +0 -4
- data/app/helpers/maily_herald_helper.rb +0 -9
- data/app/models/maily_herald/mailing_record.rb +0 -6
- data/app/views/layouts/maily_herald/application.html.erb +0 -14
- data/db/migrate/20130711124555_create_maily_herald_tables.rb +0 -38
- data/lib/maily_herald/worker.rb +0 -15
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjIwNzFmNTFiM2E1MzI0NGM0MjkxZDQyNTk2MDdkY2IzMmE1YzBjNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzBlMTQ1Mzk0ZDEzYTg5N2FhYTlmYjQ3ZGMzY2E0NTZmMGU1NTkzMQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmViMzhiN2IzMzg1NWQ0NzI0MjdlMTg3YzI0ZmZlNzU5MjY4NTdjNDJlYTM5
|
10
|
+
NThhY2Q4NGRlZjYwNjBhNDYyYTFkMDE2NTZjZjVhOWFlZmU5YTAwY2ZlZjhm
|
11
|
+
MjU2ZDg5OTZlNWEzZDk3ZjdjM2Q0YzU0Y2RmOGViNmUzNmEzMTA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODhiYzU0N2Q4YTgyNGZhNTg1OWI2NTE1NzA2NmRmODlkNGUyNjE2ODY5ZWU4
|
14
|
+
YjcwMDkyZmNlYzhhOGQ3NWNmYWE4N2I3YjUyZjdlMjFjNjY1Nzg3YTU4YTFi
|
15
|
+
YmI2MTRlNjc1ODNlYzNiNWU2MTNiNjhlODkzY2YxOGVjOTlmYTU=
|
data/.gitignore
CHANGED
@@ -1,11 +1,17 @@
|
|
1
1
|
.bundle/
|
2
2
|
log/*.log
|
3
3
|
pkg/
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
spec/dummy/db/*.sqlite3
|
5
|
+
spec/dummy/log/*.log
|
6
|
+
spec/dummy/tmp/
|
7
|
+
spec/dummy/.sass-cache
|
8
|
+
coverage/*
|
9
|
+
dump.rdb
|
10
|
+
tmp
|
11
|
+
*.gem
|
8
12
|
|
9
13
|
*.swo
|
10
14
|
*.swp
|
11
15
|
*.rvmrc
|
16
|
+
*.ruby-gemset
|
17
|
+
*.ruby-version
|
data/.rspec
ADDED
data/Gemfile
CHANGED
@@ -1,19 +1,8 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
# Declare your gem's dependencies in maily_herald.gemspec.
|
4
|
-
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
-
# development dependencies will be added by default to the :development group.
|
6
3
|
gemspec
|
7
4
|
|
8
5
|
# jquery-rails is used by the dummy application
|
9
6
|
gem "jquery-rails"
|
10
7
|
|
11
|
-
gem
|
12
|
-
|
13
|
-
# Declare any dependencies that are still in development here instead of in
|
14
|
-
# your gemspec. These might include edge Rails or gems from your path or
|
15
|
-
# Git. Remember to move these dependencies to your gemspec before releasing
|
16
|
-
# your gem to rubygems.org.
|
17
|
-
|
18
|
-
# To use debugger
|
19
|
-
# gem 'debugger'
|
8
|
+
gem 'debugger'
|
data/Gemfile.lock
CHANGED
@@ -1,26 +1,20 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git@github.com:Shopify/liquid.git
|
3
|
-
revision: fbfda1a1895bfb5bd9477248008f60fc1953c297
|
4
|
-
specs:
|
5
|
-
liquid (2.6.0)
|
6
|
-
|
7
1
|
PATH
|
8
2
|
remote: .
|
9
3
|
specs:
|
10
4
|
maily_herald (0.0.1)
|
11
|
-
liquid (~> 2.6.
|
12
|
-
rails (
|
13
|
-
sidekiq (~> 2.
|
5
|
+
liquid (~> 2.6.1)
|
6
|
+
rails (> 3.2)
|
7
|
+
sidekiq (~> 2.17.8)
|
14
8
|
|
15
9
|
GEM
|
16
10
|
remote: http://rubygems.org/
|
17
11
|
specs:
|
18
|
-
actionmailer (3.2.
|
19
|
-
actionpack (= 3.2.
|
20
|
-
mail (~> 2.5.
|
21
|
-
actionpack (3.2.
|
22
|
-
activemodel (= 3.2.
|
23
|
-
activesupport (= 3.2.
|
12
|
+
actionmailer (3.2.18)
|
13
|
+
actionpack (= 3.2.18)
|
14
|
+
mail (~> 2.5.4)
|
15
|
+
actionpack (3.2.18)
|
16
|
+
activemodel (= 3.2.18)
|
17
|
+
activesupport (= 3.2.18)
|
24
18
|
builder (~> 3.0.0)
|
25
19
|
erubis (~> 2.7.0)
|
26
20
|
journey (~> 1.0.4)
|
@@ -28,122 +22,175 @@ GEM
|
|
28
22
|
rack-cache (~> 1.2)
|
29
23
|
rack-test (~> 0.6.1)
|
30
24
|
sprockets (~> 2.2.1)
|
31
|
-
activemodel (3.2.
|
32
|
-
activesupport (= 3.2.
|
25
|
+
activemodel (3.2.18)
|
26
|
+
activesupport (= 3.2.18)
|
33
27
|
builder (~> 3.0.0)
|
34
|
-
activerecord (3.2.
|
35
|
-
activemodel (= 3.2.
|
36
|
-
activesupport (= 3.2.
|
28
|
+
activerecord (3.2.18)
|
29
|
+
activemodel (= 3.2.18)
|
30
|
+
activesupport (= 3.2.18)
|
37
31
|
arel (~> 3.0.2)
|
38
32
|
tzinfo (~> 0.3.29)
|
39
|
-
activeresource (3.2.
|
40
|
-
activemodel (= 3.2.
|
41
|
-
activesupport (= 3.2.
|
42
|
-
activesupport (3.2.
|
43
|
-
i18n (
|
33
|
+
activeresource (3.2.18)
|
34
|
+
activemodel (= 3.2.18)
|
35
|
+
activesupport (= 3.2.18)
|
36
|
+
activesupport (3.2.18)
|
37
|
+
i18n (~> 0.6, >= 0.6.4)
|
44
38
|
multi_json (~> 1.0)
|
45
|
-
arel (3.0.
|
46
|
-
bourne (1.5.0)
|
47
|
-
mocha (>= 0.13.2, < 0.15)
|
39
|
+
arel (3.0.3)
|
48
40
|
builder (3.0.4)
|
49
|
-
celluloid (0.
|
50
|
-
timers (
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
celluloid (0.15.2)
|
42
|
+
timers (~> 1.1.0)
|
43
|
+
coderay (1.1.0)
|
44
|
+
columnize (0.8.9)
|
45
|
+
connection_pool (2.0.0)
|
46
|
+
database_cleaner (1.3.0)
|
47
|
+
debugger (1.6.8)
|
48
|
+
columnize (>= 0.3.1)
|
49
|
+
debugger-linecache (~> 1.2.0)
|
50
|
+
debugger-ruby_core_source (~> 1.3.5)
|
51
|
+
debugger-linecache (1.2.0)
|
52
|
+
debugger-ruby_core_source (1.3.5)
|
53
|
+
diff-lcs (1.2.5)
|
54
|
+
docile (1.1.3)
|
54
55
|
erubis (2.7.0)
|
55
|
-
factory_girl (4.
|
56
|
+
factory_girl (4.4.0)
|
56
57
|
activesupport (>= 3.0.0)
|
57
|
-
factory_girl_rails (4.
|
58
|
-
factory_girl (~> 4.
|
58
|
+
factory_girl_rails (4.4.1)
|
59
|
+
factory_girl (~> 4.4.0)
|
59
60
|
railties (>= 3.0.0)
|
61
|
+
ffi (1.9.3)
|
62
|
+
formatador (0.2.5)
|
63
|
+
guard (2.6.1)
|
64
|
+
formatador (>= 0.2.4)
|
65
|
+
listen (~> 2.7)
|
66
|
+
lumberjack (~> 1.0)
|
67
|
+
pry (>= 0.9.12)
|
68
|
+
thor (>= 0.18.1)
|
69
|
+
guard-rspec (4.2.10)
|
70
|
+
guard (~> 2.1)
|
71
|
+
rspec (>= 2.14, < 4.0)
|
60
72
|
hike (1.2.3)
|
61
|
-
i18n (0.6.
|
73
|
+
i18n (0.6.9)
|
62
74
|
journey (1.0.4)
|
63
|
-
jquery-rails (3.0
|
75
|
+
jquery-rails (3.1.0)
|
64
76
|
railties (>= 3.0, < 5.0)
|
65
77
|
thor (>= 0.14, < 2.0)
|
66
|
-
json (1.8.
|
78
|
+
json (1.8.1)
|
79
|
+
liquid (2.6.1)
|
80
|
+
listen (2.7.7)
|
81
|
+
celluloid (>= 0.15.2)
|
82
|
+
rb-fsevent (>= 0.9.3)
|
83
|
+
rb-inotify (>= 0.9)
|
84
|
+
lumberjack (1.0.6)
|
67
85
|
mail (2.5.4)
|
68
86
|
mime-types (~> 1.16)
|
69
87
|
treetop (~> 1.4.8)
|
70
|
-
|
71
|
-
mime-types (1.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
88
|
+
method_source (0.8.2)
|
89
|
+
mime-types (1.25.1)
|
90
|
+
multi_json (1.10.1)
|
91
|
+
polyglot (0.3.5)
|
92
|
+
pry (0.10.0)
|
93
|
+
coderay (~> 1.1.0)
|
94
|
+
method_source (~> 0.8.1)
|
95
|
+
slop (~> 3.4)
|
76
96
|
rack (1.4.5)
|
77
97
|
rack-cache (1.2)
|
78
98
|
rack (>= 0.4)
|
79
|
-
rack-ssl (1.3.
|
99
|
+
rack-ssl (1.3.4)
|
80
100
|
rack
|
81
101
|
rack-test (0.6.2)
|
82
102
|
rack (>= 1.0)
|
83
|
-
rails (3.2.
|
84
|
-
actionmailer (= 3.2.
|
85
|
-
actionpack (= 3.2.
|
86
|
-
activerecord (= 3.2.
|
87
|
-
activeresource (= 3.2.
|
88
|
-
activesupport (= 3.2.
|
103
|
+
rails (3.2.18)
|
104
|
+
actionmailer (= 3.2.18)
|
105
|
+
actionpack (= 3.2.18)
|
106
|
+
activerecord (= 3.2.18)
|
107
|
+
activeresource (= 3.2.18)
|
108
|
+
activesupport (= 3.2.18)
|
89
109
|
bundler (~> 1.0)
|
90
|
-
railties (= 3.2.
|
91
|
-
railties (3.2.
|
92
|
-
actionpack (= 3.2.
|
93
|
-
activesupport (= 3.2.
|
110
|
+
railties (= 3.2.18)
|
111
|
+
railties (3.2.18)
|
112
|
+
actionpack (= 3.2.18)
|
113
|
+
activesupport (= 3.2.18)
|
94
114
|
rack-ssl (~> 1.3.2)
|
95
115
|
rake (>= 0.8.7)
|
96
116
|
rdoc (~> 3.4)
|
97
117
|
thor (>= 0.14.6, < 2.0)
|
98
|
-
rake (10.
|
118
|
+
rake (10.3.2)
|
119
|
+
rb-fsevent (0.9.4)
|
120
|
+
rb-inotify (0.9.5)
|
121
|
+
ffi (>= 0.5.0)
|
99
122
|
rdoc (3.12.2)
|
100
123
|
json (~> 1.4)
|
101
|
-
|
102
|
-
redis
|
103
|
-
|
104
|
-
|
105
|
-
rspec
|
106
|
-
|
107
|
-
|
108
|
-
|
124
|
+
redcarpet (3.2.2)
|
125
|
+
redis (3.1.0)
|
126
|
+
redis-namespace (1.5.1)
|
127
|
+
redis (~> 3.0, >= 3.0.4)
|
128
|
+
rspec (3.0.0)
|
129
|
+
rspec-core (~> 3.0.0)
|
130
|
+
rspec-expectations (~> 3.0.0)
|
131
|
+
rspec-mocks (~> 3.0.0)
|
132
|
+
rspec-core (3.0.0)
|
133
|
+
rspec-support (~> 3.0.0)
|
134
|
+
rspec-expectations (3.0.0)
|
135
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
136
|
+
rspec-support (~> 3.0.0)
|
137
|
+
rspec-mocks (3.0.1)
|
138
|
+
rspec-support (~> 3.0.0)
|
139
|
+
rspec-rails (3.0.1)
|
109
140
|
actionpack (>= 3.0)
|
110
141
|
activesupport (>= 3.0)
|
111
142
|
railties (>= 3.0)
|
112
|
-
rspec-core (~>
|
113
|
-
rspec-expectations (~>
|
114
|
-
rspec-mocks (~>
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
connection_pool (>= 1.0.0)
|
143
|
+
rspec-core (~> 3.0.0)
|
144
|
+
rspec-expectations (~> 3.0.0)
|
145
|
+
rspec-mocks (~> 3.0.0)
|
146
|
+
rspec-support (~> 3.0.0)
|
147
|
+
rspec-support (3.0.0)
|
148
|
+
sidekiq (2.17.8)
|
149
|
+
celluloid (= 0.15.2)
|
150
|
+
connection_pool (~> 2.0)
|
121
151
|
json
|
122
|
-
redis (
|
123
|
-
redis-namespace
|
152
|
+
redis (~> 3.1)
|
153
|
+
redis-namespace (~> 1.3)
|
154
|
+
simplecov (0.8.2)
|
155
|
+
docile (~> 1.1.0)
|
156
|
+
multi_json
|
157
|
+
simplecov-html (~> 0.8.0)
|
158
|
+
simplecov-html (0.8.0)
|
159
|
+
slop (3.5.0)
|
160
|
+
spring (1.1.3)
|
161
|
+
spring-commands-rspec (1.0.2)
|
162
|
+
spring (>= 0.9.1)
|
124
163
|
sprockets (2.2.2)
|
125
164
|
hike (~> 1.2)
|
126
165
|
multi_json (~> 1.0)
|
127
166
|
rack (~> 1.0)
|
128
167
|
tilt (~> 1.1, != 1.3.0)
|
129
|
-
sqlite3 (1.3.
|
130
|
-
thor (0.
|
168
|
+
sqlite3 (1.3.9)
|
169
|
+
thor (0.19.1)
|
131
170
|
tilt (1.4.1)
|
171
|
+
timecop (0.7.1)
|
132
172
|
timers (1.1.0)
|
133
|
-
treetop (1.4.
|
173
|
+
treetop (1.4.15)
|
134
174
|
polyglot
|
135
175
|
polyglot (>= 0.3.1)
|
136
|
-
tzinfo (0.3.
|
176
|
+
tzinfo (0.3.41)
|
177
|
+
yard (0.8.7.6)
|
137
178
|
|
138
179
|
PLATFORMS
|
139
180
|
ruby
|
140
181
|
|
141
182
|
DEPENDENCIES
|
142
183
|
database_cleaner
|
184
|
+
debugger
|
143
185
|
factory_girl_rails
|
186
|
+
guard
|
187
|
+
guard-rspec
|
144
188
|
jquery-rails
|
145
|
-
liquid (~> 2.6.0)!
|
146
189
|
maily_herald!
|
190
|
+
redcarpet
|
147
191
|
rspec-rails
|
148
|
-
|
192
|
+
simplecov
|
193
|
+
spring-commands-rspec
|
149
194
|
sqlite3
|
195
|
+
timecop
|
196
|
+
yard
|
data/Guardfile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec, :version => 2, :cmd => "spring rspec" do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara features specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
|
24
|
+
notification :notifysend
|
25
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
MailyHerald - Ruby on Rails email marketing solution.
|
2
|
+
|
3
|
+
Copyright (c) 2013-2015 Sology (http://www.sology.eu)
|
4
|
+
with initial development sponsored by
|
5
|
+
Smart Language Apps Ltd <http://www.smartlanguageapps.com>.
|
6
|
+
|
7
|
+
MailyHerald is an Open Source project licensed under the terms of
|
8
|
+
the LGPLv3 license.
|
9
|
+
Please see <http://www.gnu.org/licenses/lgpl-3.0.html>
|
10
|
+
for license text.
|
data/README.md
ADDED
@@ -0,0 +1,346 @@
|
|
1
|
+
# MailyHerald
|
2
|
+
|
3
|
+
MailyHerald is a Ruby on Rails gem that helps you sending and managing your mailings. Think of Maily as a self-hosted Mailchimp alternative you can easily integrate with your site. MailyHerald is great both for email marketing and conducting daily stream of notifications you send to your users.
|
4
|
+
|
5
|
+
With MailyHerald you can send:
|
6
|
+
* one-time mailings (i.e. welcome emails, special offers),
|
7
|
+
* periodical mailings (i.e. weekly notifications, reminders),
|
8
|
+
* mailing sequences - multiple ordered emails delivered with certain delays since specific point in time (i.e. onboarding emails, site feature overview).
|
9
|
+
|
10
|
+
Maily keeps track of user subscriptions and allow them to easily opt out. You can define who receives which emails and specify conditions that control delivery. All deliveries are tracked and logged. Periodical and Sequence mailing deliveries are scheduled individually for each recipient.
|
11
|
+
|
12
|
+
Maily seamlessly integrates with your app. It can use your regular Mailers or you can build ad-hoc mailings with [Liquid](http://liquidmarkup.org/) markup templates.
|
13
|
+
|
14
|
+
Core Maily features are accessible for Rails programmers via API. Apart from that, Maily has a nice web UI provided by separate [maily_herald-webui](https://github.com/Sology/maily_herald-webui) gem.
|
15
|
+
|
16
|
+
## Requirements
|
17
|
+
|
18
|
+
Both Ruby on Rails 3.2 and 4 are supported.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Simply just
|
23
|
+
|
24
|
+
gem install maily_herald
|
25
|
+
|
26
|
+
or put in your Gemfile
|
27
|
+
|
28
|
+
gem "maily_herald"
|
29
|
+
|
30
|
+
## Features
|
31
|
+
|
32
|
+
* Designed for Ruby on Rails
|
33
|
+
* Self-hosted
|
34
|
+
* Seamless and flexible integration
|
35
|
+
* Asynchronous processing
|
36
|
+
* Individual delivery scheduling
|
37
|
+
* Great both for developers (API) and end-users (Web UI)
|
38
|
+
* Ad-hoc email templating using [Liquid](http://liquidmarkup.org/) syntax
|
39
|
+
* Three different mailing types
|
40
|
+
* User-friendly subscription management i.e. via automatic & personal opt-out links
|
41
|
+
* Correspondence logging
|
42
|
+
* Mailing conditions
|
43
|
+
|
44
|
+
## Development state
|
45
|
+
|
46
|
+
MailyHerald is relatively young piece of software and can't be considered stable. Although it has been deployed to few production environments for quite some time now, we can't guarantee it will suite your needs too.
|
47
|
+
|
48
|
+
If you decide to use it, please tell us what you think about it, post some issues on GitHub etc. We're waiting for your feedback.
|
49
|
+
|
50
|
+
Here are some things we would like to implement in the future:
|
51
|
+
|
52
|
+
* better mailing scheduling,
|
53
|
+
* message analytics,
|
54
|
+
* link tracking,
|
55
|
+
* better Web UI,
|
56
|
+
* _put your beloved feature here_.
|
57
|
+
|
58
|
+
## How it works
|
59
|
+
|
60
|
+
There are few key concepts that need to be explained in order to understand how Maily works. Some of them are similar to what you might know form other conventional email marketing software. Others come strictly from Ruby on Rails world.
|
61
|
+
|
62
|
+
**Entities**
|
63
|
+
|
64
|
+
Entities are basically your mailing recipients. They will be probably represented in your application by `User` model.
|
65
|
+
|
66
|
+
**Mailings**
|
67
|
+
|
68
|
+
You usually send single emails to your users - one at a time. Mailing is a bunch of emails sent out to many users. MailyHerald allows you to send three types of Mailings: one-times, periodicals and sequences.
|
69
|
+
|
70
|
+
**Contexts**
|
71
|
+
|
72
|
+
Maily Contexts are abstraction layer for accessing collections of entities and their attributes.
|
73
|
+
|
74
|
+
There are three main things that Contexts do:
|
75
|
+
|
76
|
+
* They define sets of entities via Rails scopes (i.e. `User.activated` meaning all application users that activated their accounts).
|
77
|
+
* They specify destination email addresses for entities (i.e. you can define that `User#email` method returns email address or specify a custom proc that does that).
|
78
|
+
* They specify additional entity attributes that can be used inside Mailing templates, conditions etc. (basically - attributes accessible via Liquid).
|
79
|
+
|
80
|
+
**Lists and Subscriptions**
|
81
|
+
|
82
|
+
Lists are sets of entities that receive certain mailings. Entities are added to Lists by creating Subscriptions. It is entirely up to you how you manage subscriptions in application. Typically, you put some checkbox in user's profile page that subscribes and unsubscribes them from mailing lists.
|
83
|
+
|
84
|
+
Each Subscription has it's unique token allowing users to be provided with one click opt-out link.
|
85
|
+
|
86
|
+
**Mailers**
|
87
|
+
|
88
|
+
Mailers are standard way of sending emails in Rails applications. MailyHerald hooks into ActionMailer internals and allows you to send Mailings just like you send your regular emails. All you need to do is inherit `MailyHerald::Mailer` in your Mailer.
|
89
|
+
|
90
|
+
There's also a possibility to send Mailings without using any of your custom Mailers. `MailyHerald::Mailer` is in this case used implicitly; email body and subject is stored directly in your Mailing definition as a Liquid template. Liquid gives you access to entity attributes defined in the Context. This way of creating Mailings is especially useful within Web UI where you can build new Mailing by just typing its template.
|
91
|
+
|
92
|
+
**Delivery**
|
93
|
+
|
94
|
+
MailyHerald uses great gem [Sidekiq](http://sidekiq.org/) to process deliveries in the background. This applies to Periodical and Sequence Mailings - their delivieries are scheduled individually for each entity on the subscription list.
|
95
|
+
|
96
|
+
Maily needs to check periodically for scheduled mailings and if their time come - queue them for delivery. This is job for MailyHerald Paperboy - tiny daemon that runs in the background and check the schedules. It is essential to make you periodical and sequence mailings work.
|
97
|
+
|
98
|
+
## Usage
|
99
|
+
|
100
|
+
Let's assume your entities are your `User` model objects. Read on in order to find out how to start with Maily.
|
101
|
+
|
102
|
+
### Migrations
|
103
|
+
|
104
|
+
Install engine migrations and run them.
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
rake maily_herald:install:migrations
|
108
|
+
rake db:migrate
|
109
|
+
```
|
110
|
+
|
111
|
+
### Defaults (optional)
|
112
|
+
|
113
|
+
In some cases, you need to specify default `from` and `host` mailer options in order to ensure proper email rendering:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
config.action_mailer.default_options = { from: "hello@mailyherald.org" }
|
117
|
+
config.action_mailer.default_url_options = { host: "mailyherald.org" }
|
118
|
+
|
119
|
+
```
|
120
|
+
|
121
|
+
### Initializer
|
122
|
+
|
123
|
+
Generate and setup an initializer.
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
rails g maily_herald:install
|
127
|
+
```
|
128
|
+
|
129
|
+
This will create the following file:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
# config/initializers/maily_herald.rb
|
133
|
+
MailyHerald.setup do |config|
|
134
|
+
# Put your contexts, mailing definitions etc. here.
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
There are few things you need to put there.
|
139
|
+
|
140
|
+
**Set up your context**
|
141
|
+
|
142
|
+
Say for example, you want to deliver your mailings to all your active users:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
config.context :active_users do |context|
|
146
|
+
context.scope {User.active}
|
147
|
+
context.destination {|user| user.email}
|
148
|
+
|
149
|
+
# Alternatively, you can specify destination as attribute name:
|
150
|
+
# context.destination = :email
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
**Set up your lists**
|
155
|
+
|
156
|
+
Following means that all users in `:active_users` context scope can be subscribed to `:newsletters` list.
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
config.list :newsletters do |list|
|
160
|
+
list.context_name = :active_users
|
161
|
+
end
|
162
|
+
```
|
163
|
+
|
164
|
+
**Set up your mailings**
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
config.one_time_mailing :hello do |mailing|
|
168
|
+
mailing.title = "Hello mailing"
|
169
|
+
mailing.context_name = :active_users
|
170
|
+
mailing.mailer_name = "UserMailer"
|
171
|
+
mailing.enable # mailings are disabled by default
|
172
|
+
end
|
173
|
+
|
174
|
+
config.periodical_mailing :weekly_newsletter do |mailing|
|
175
|
+
mailing.title = "Weekly newsletter"
|
176
|
+
mailing.context_name = :active_users
|
177
|
+
mailing.mailer_name = "UserMailer"
|
178
|
+
mailing.enable
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
### Mailers
|
183
|
+
|
184
|
+
You don't need to have any Mailer to use MailyHerald. It works perfectly fine with its generic `MailyHerald::Mailer` and mailing templates written in Luquid.
|
185
|
+
|
186
|
+
But if you still want your fancy Mailer views and features, you need to modify it a bit.
|
187
|
+
|
188
|
+
First, each Mailer you want to use with MailyHerald needs to extend `MailyHerald::Mailer` class.
|
189
|
+
Then each Mailer method must be named after mailing identification name and accept only one parameter which is your entity (i.e. `User` class object).
|
190
|
+
|
191
|
+
This setup gives you some extra instance variables available in your views:
|
192
|
+
|
193
|
+
* `@maily_entity` - entity you are sending this email to,
|
194
|
+
* `@maily_mailing` - Mailing you are sending,
|
195
|
+
* `@maily_subscription` - `MailyHerald::Subscription` object related to this entity and Mailing,
|
196
|
+
|
197
|
+
Here's the complete example:
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
class UserMailer < MailyHerald::Mailer
|
201
|
+
def hello user
|
202
|
+
mail :subject => "Hi there #{user.name}!"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
### Opt-outs
|
208
|
+
|
209
|
+
MailyHerald allows entities to easily opt-out using direct unsubscribe urls. Each entity subscription has its own token and based on this token, opt-out URL is generated.
|
210
|
+
|
211
|
+
To process user opt-out requests you need to mount Maily into your app:
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
# config/routes.rb
|
215
|
+
|
216
|
+
mount MailyHerald::Engine => "/unsubscribe", :as => "maily_herald_engine"
|
217
|
+
```
|
218
|
+
|
219
|
+
Maily provides you with URL helper that generates opt-out URLs (i.e. in your ActionMailer views):
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
maily_herald_engine.unsubscribe_url(@maily_subscription)
|
223
|
+
```
|
224
|
+
|
225
|
+
When you use Liquid for email templating, you should use following syntax:
|
226
|
+
```
|
227
|
+
{{subscription.token_url}}
|
228
|
+
```
|
229
|
+
|
230
|
+
Visiting opt-out url disables subscription and by default redirects to "/".
|
231
|
+
|
232
|
+
### Delivery
|
233
|
+
|
234
|
+
From now on, Maily will handle and track your regular mail deliveries:
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
UserMailer.hello(User.first).deliver
|
238
|
+
```
|
239
|
+
|
240
|
+
Of course, you can also run the mailing for all users in scope at once:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
MailyHerald.dispatch(:hello).run
|
244
|
+
```
|
245
|
+
|
246
|
+
See [API Docs](http://www.rubydoc.info/gems/maily_herald) for more details about delivery methods.
|
247
|
+
|
248
|
+
### Background processing
|
249
|
+
|
250
|
+
Start MailyHerald Paperboy which will take care of your other periodical and sequence deliveries:
|
251
|
+
|
252
|
+
```
|
253
|
+
$ maily_herald paperboy --start
|
254
|
+
```
|
255
|
+
|
256
|
+
**That's it!**
|
257
|
+
|
258
|
+
Your Maily setup is now complete.
|
259
|
+
|
260
|
+
## Configuring
|
261
|
+
|
262
|
+
You can configure your Maily using config file `config/maily_herald.yml`. Supported options:
|
263
|
+
|
264
|
+
* `verbose`: true,false
|
265
|
+
* `logfile`: where all the stuff is logged, usually 'log/maily_herald.log`
|
266
|
+
* `pidfile`: file name
|
267
|
+
* `redis_url`: string
|
268
|
+
* `redis_namespace`: string
|
269
|
+
* `redis_driver`: string
|
270
|
+
|
271
|
+
## Customizing
|
272
|
+
|
273
|
+
### Opt-out URLs
|
274
|
+
|
275
|
+
By default, visiting opt-out URL disables subscription and redirects to "/". You can easily customize the redirect path by specifying `token_redirect` proc:
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
# Evaluated within config:
|
279
|
+
config.token_redirect do |controller, subscription|
|
280
|
+
# This is just an example, put here whatever you want.
|
281
|
+
controller.view_context.unsubscribed_path
|
282
|
+
end
|
283
|
+
```
|
284
|
+
|
285
|
+
In case you need more customization, you can always overwrite `MailyHerald::TokensController` and its `get` method:
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
# app/controllers/maily_herald/tokens_controller.rb
|
289
|
+
module MailyHerald
|
290
|
+
class TokensController < ::ApplicationController
|
291
|
+
before_action :find_subscription
|
292
|
+
|
293
|
+
def get
|
294
|
+
if @subscription && @subscription.active?
|
295
|
+
@subscription.deactivate!
|
296
|
+
# now render some custom view
|
297
|
+
else
|
298
|
+
redirect_to(main_app.root_url)
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
private
|
303
|
+
|
304
|
+
def find_subscription
|
305
|
+
@subscription ||= MailyHerald::Subscription.find_by_token(params[:token])
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
```
|
310
|
+
|
311
|
+
### Redis namespaces
|
312
|
+
|
313
|
+
If you want to use MailyHerald with non-standard Redis namespace, make sure your Sidekiq is also configured properly. This usually involves creating initializer file:
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
# config/initializers/sidekiq.rb
|
317
|
+
Sidekiq.configure_server do |config|
|
318
|
+
config.redis = { namespace: 'maily' }
|
319
|
+
end
|
320
|
+
Sidekiq.configure_client do |config|
|
321
|
+
config.redis = { namespace: 'maily' }
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
325
|
+
Then of course you need to tell Maily about that too:
|
326
|
+
|
327
|
+
```yaml
|
328
|
+
# config/maily_herald.yml
|
329
|
+
---
|
330
|
+
:redis_namespace: maily
|
331
|
+
```
|
332
|
+
|
333
|
+
## More Information
|
334
|
+
|
335
|
+
* [Home Page](http://www.mailyherald.org)
|
336
|
+
* [API Docs](http://www.rubydoc.info/gems/maily_herald)
|
337
|
+
* Showcase (_coming soon_)
|
338
|
+
* [Sample application](https://github.com/Sology/maily_testapp)
|
339
|
+
|
340
|
+
For bug reports or feature requests see the [issues on Github](https://github.com/Sology/maily_herald/issues).
|
341
|
+
|
342
|
+
## License
|
343
|
+
|
344
|
+
LGPLv3 License. Copyright 2013-2015 Sology. http://www.sology.eu
|
345
|
+
|
346
|
+
Initial development sponsored by Smart Language Apps Limited http://smartlanguageapps.com/
|