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.
Files changed (93) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +10 -4
  3. data/.rspec +5 -0
  4. data/Gemfile +1 -12
  5. data/Gemfile.lock +129 -82
  6. data/Guardfile +25 -0
  7. data/LICENSE +10 -0
  8. data/README.md +346 -0
  9. data/Rakefile +5 -0
  10. data/app/controllers/maily_herald/tokens_controller.rb +11 -0
  11. data/app/helpers/maily_herald/tokens_helper.rb +17 -0
  12. data/app/mailers/maily_herald/mailer.rb +91 -0
  13. data/app/models/maily_herald/dispatch.rb +76 -0
  14. data/app/models/maily_herald/list.rb +99 -0
  15. data/app/models/maily_herald/log.rb +67 -0
  16. data/app/models/maily_herald/mailing.rb +139 -7
  17. data/app/models/maily_herald/one_time_mailing.rb +26 -0
  18. data/app/models/maily_herald/periodical_mailing.rb +145 -0
  19. data/app/models/maily_herald/sequence.rb +169 -2
  20. data/app/models/maily_herald/sequence_mailing.rb +71 -0
  21. data/app/models/maily_herald/subscription.rb +67 -0
  22. data/bin/maily_herald +16 -0
  23. data/config/database.yml +5 -0
  24. data/config/locales/en.yml +6 -11
  25. data/config/routes.rb +10 -0
  26. data/config/spring.rb +1 -0
  27. data/db/migrate/20150205120443_create_maily_herald_tables.rb +53 -0
  28. data/db/migrate_legacy/20130711124555_create_maily_herald_tables.rb +67 -0
  29. data/db/migrate_legacy/20140612101023_create_lists.rb +33 -0
  30. data/lib/generators/maily_herald/install_generator.rb +3 -3
  31. data/lib/generators/templates/README +2 -0
  32. data/lib/generators/templates/maily_herald.rb +1 -0
  33. data/lib/maily_herald.rb +345 -23
  34. data/lib/maily_herald/autonaming.rb +34 -0
  35. data/lib/maily_herald/capistrano.rb +5 -0
  36. data/lib/maily_herald/capistrano/tasks.cap +67 -0
  37. data/lib/maily_herald/capistrano/tasks2.rb +20 -0
  38. data/lib/maily_herald/cli.rb +293 -0
  39. data/lib/maily_herald/condition_evaluator.rb +82 -0
  40. data/lib/maily_herald/config.rb +5 -0
  41. data/lib/maily_herald/context.rb +223 -77
  42. data/lib/maily_herald/engine.rb +17 -0
  43. data/lib/maily_herald/logging.rb +90 -0
  44. data/lib/maily_herald/manager.rb +53 -0
  45. data/lib/maily_herald/model_extensions.rb +15 -0
  46. data/lib/maily_herald/template_renderer.rb +16 -0
  47. data/lib/maily_herald/utils.rb +78 -5
  48. data/lib/maily_herald/version.rb +1 -1
  49. data/maily_herald.gemspec +17 -9
  50. data/spec/controllers/maily_herald/tokens_controller_spec.rb +81 -0
  51. data/spec/dummy/Guardfile +35 -0
  52. data/spec/dummy/app/mailers/test_mailer.rb +11 -0
  53. data/spec/dummy/app/models/product.rb +2 -0
  54. data/spec/dummy/app/models/user.rb +4 -0
  55. data/spec/dummy/app/views/test_mailer/sample_mail.text.erb +1 -0
  56. data/spec/dummy/bin/rails +10 -0
  57. data/spec/dummy/bin/rake +7 -0
  58. data/spec/dummy/bin/rspec +7 -0
  59. data/spec/dummy/bin/spring +18 -0
  60. data/spec/dummy/config/application.rb +1 -1
  61. data/spec/dummy/config/environments/development.rb +1 -0
  62. data/spec/dummy/config/environments/test.rb +1 -0
  63. data/spec/dummy/config/initializers/maily_herald.rb +103 -0
  64. data/spec/dummy/config/locales/maily_herald.en.yml +28 -0
  65. data/spec/dummy/db/migrate/20130723074347_create_users.rb +18 -0
  66. data/spec/dummy/db/schema.rb +82 -0
  67. data/spec/factories/products.rb +5 -0
  68. data/spec/factories/users.rb +11 -0
  69. data/spec/lib/context_spec.rb +41 -0
  70. data/spec/lib/maily_herald_spec.rb +32 -0
  71. data/spec/lib/utils_spec.rb +48 -0
  72. data/spec/mailers/maily_herald/mailer_spec.rb +38 -0
  73. data/spec/models/maily_herald/list_spec.rb +64 -0
  74. data/spec/models/maily_herald/log_spec.rb +36 -0
  75. data/spec/models/maily_herald/mailing_spec.rb +34 -0
  76. data/spec/models/maily_herald/one_time_mailing_spec.rb +112 -0
  77. data/spec/models/maily_herald/periodical_mailing_spec.rb +339 -0
  78. data/spec/models/maily_herald/sequence_mailing_spec.rb +18 -0
  79. data/spec/models/maily_herald/sequence_spec.rb +429 -0
  80. data/spec/models/maily_herald/subscription_spec.rb +32 -0
  81. data/spec/spec_helper.rb +31 -11
  82. metadata +199 -54
  83. data/MIT-LICENSE +0 -20
  84. data/README.rdoc +0 -3
  85. data/app/assets/images/maily_herald/.gitkeep +0 -0
  86. data/app/assets/javascripts/maily_herald/application.js +0 -15
  87. data/app/assets/stylesheets/maily_herald/application.css +0 -13
  88. data/app/helpers/maily_herald/application_helper.rb +0 -4
  89. data/app/helpers/maily_herald_helper.rb +0 -9
  90. data/app/models/maily_herald/mailing_record.rb +0 -6
  91. data/app/views/layouts/maily_herald/application.html.erb +0 -14
  92. data/db/migrate/20130711124555_create_maily_herald_tables.rb +0 -38
  93. data/lib/maily_herald/worker.rb +0 -15
@@ -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
- test/dummy/db/*.sqlite3
5
- test/dummy/log/*.log
6
- test/dummy/tmp/
7
- test/dummy/.sass-cache
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
@@ -0,0 +1,5 @@
1
+ --color
2
+ #--format=documentation
3
+ --backtrace
4
+ --profile
5
+ --order random
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 "liquid", "~> 2.6.0", :git => "git@github.com:Shopify/liquid.git"
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'
@@ -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.0)
12
- rails (~> 3.2.8)
13
- sidekiq (~> 2.13.0)
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.13)
19
- actionpack (= 3.2.13)
20
- mail (~> 2.5.3)
21
- actionpack (3.2.13)
22
- activemodel (= 3.2.13)
23
- activesupport (= 3.2.13)
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.13)
32
- activesupport (= 3.2.13)
25
+ activemodel (3.2.18)
26
+ activesupport (= 3.2.18)
33
27
  builder (~> 3.0.0)
34
- activerecord (3.2.13)
35
- activemodel (= 3.2.13)
36
- activesupport (= 3.2.13)
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.13)
40
- activemodel (= 3.2.13)
41
- activesupport (= 3.2.13)
42
- activesupport (3.2.13)
43
- i18n (= 0.6.1)
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.2)
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.14.1)
50
- timers (>= 1.0.0)
51
- connection_pool (1.1.0)
52
- database_cleaner (1.0.1)
53
- diff-lcs (1.2.4)
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.2.0)
56
+ factory_girl (4.4.0)
56
57
  activesupport (>= 3.0.0)
57
- factory_girl_rails (4.2.1)
58
- factory_girl (~> 4.2.0)
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.1)
73
+ i18n (0.6.9)
62
74
  journey (1.0.4)
63
- jquery-rails (3.0.2)
75
+ jquery-rails (3.1.0)
64
76
  railties (>= 3.0, < 5.0)
65
77
  thor (>= 0.14, < 2.0)
66
- json (1.8.0)
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
- metaclass (0.0.1)
71
- mime-types (1.23)
72
- mocha (0.14.0)
73
- metaclass (~> 0.0.1)
74
- multi_json (1.7.7)
75
- polyglot (0.3.3)
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.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.13)
84
- actionmailer (= 3.2.13)
85
- actionpack (= 3.2.13)
86
- activerecord (= 3.2.13)
87
- activeresource (= 3.2.13)
88
- activesupport (= 3.2.13)
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.13)
91
- railties (3.2.13)
92
- actionpack (= 3.2.13)
93
- activesupport (= 3.2.13)
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.1.0)
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
- redis (3.0.4)
102
- redis-namespace (1.3.0)
103
- redis (~> 3.0.0)
104
- rspec-core (2.13.1)
105
- rspec-expectations (2.13.0)
106
- diff-lcs (>= 1.1.3, < 2.0)
107
- rspec-mocks (2.13.1)
108
- rspec-rails (2.13.2)
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 (~> 2.13.0)
113
- rspec-expectations (~> 2.13.0)
114
- rspec-mocks (~> 2.13.0)
115
- shoulda-matchers (1.5.6)
116
- activesupport (>= 3.0.0)
117
- bourne (~> 1.3)
118
- sidekiq (2.13.0)
119
- celluloid (>= 0.14.1)
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 (>= 3.0)
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.7)
130
- thor (0.18.1)
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.14)
173
+ treetop (1.4.15)
134
174
  polyglot
135
175
  polyglot (>= 0.3.1)
136
- tzinfo (0.3.37)
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
- shoulda-matchers (~> 1.0)
192
+ simplecov
193
+ spring-commands-rspec
149
194
  sqlite3
195
+ timecop
196
+ yard
@@ -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.
@@ -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/