mjml-premailer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +29 -0
  6. data/.travis.yml +20 -0
  7. data/CHANGELOG.md +2 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE +202 -0
  10. data/Makefile +13 -0
  11. data/README.md +98 -0
  12. data/Rakefile +7 -0
  13. data/VERSION +1 -0
  14. data/example/.gitignore +16 -0
  15. data/example/Gemfile +10 -0
  16. data/example/README.md +10 -0
  17. data/example/Rakefile +6 -0
  18. data/example/app/assets/stylesheets/email.css +32 -0
  19. data/example/app/mailers/example_mailer.rb +9 -0
  20. data/example/app/views/example_mailer/_wrapper.html.erb +3 -0
  21. data/example/app/views/example_mailer/test_message.html.erb +9 -0
  22. data/example/app/views/layout/mail.html.erb +7 -0
  23. data/example/bin/rails +4 -0
  24. data/example/config.ru +4 -0
  25. data/example/config/application.rb +12 -0
  26. data/example/config/boot.rb +3 -0
  27. data/example/config/environment.rb +5 -0
  28. data/example/config/environments/development.rb +9 -0
  29. data/example/config/environments/production.rb +9 -0
  30. data/example/config/initializers/assets.rb +2 -0
  31. data/example/config/routes.rb +3 -0
  32. data/example/config/secrets.yml +2 -0
  33. data/example/test/mailers/previews/example_mailer_preview.rb +5 -0
  34. data/lib/mjml-premailer.rb +31 -0
  35. data/lib/mjml-premailer/find_executable.rb +11 -0
  36. data/lib/mjml-premailer/hook.rb +97 -0
  37. data/lib/mjml-premailer/railtie.rb +7 -0
  38. data/lib/mjml-premailer/version.rb +5 -0
  39. data/mjml-premailer.gemspec +26 -0
  40. data/spec/integration/delivery_spec.rb +25 -0
  41. data/spec/rails_app/app/mailers/application_mailer.rb +4 -0
  42. data/spec/rails_app/app/mailers/welcome_mailer.rb +6 -0
  43. data/spec/rails_app/app/views/layouts/mail.html.erb +7 -0
  44. data/spec/rails_app/app/views/welcome_mailer/_wrapper.html.erb +3 -0
  45. data/spec/rails_app/app/views/welcome_mailer/welcome_email.html.erb +11 -0
  46. data/spec/rails_app/config.ru +5 -0
  47. data/spec/rails_app/config/application.rb +13 -0
  48. data/spec/rails_app/config/boot.rb +5 -0
  49. data/spec/rails_app/config/environment.rb +2 -0
  50. data/spec/rails_app/config/environments/test.rb +10 -0
  51. data/spec/rails_app/config/initializers/assets.rb +1 -0
  52. data/spec/rails_app/config/routes.rb +3 -0
  53. data/spec/spec_helper.rb +18 -0
  54. data/spec/unit/config_spec.rb +20 -0
  55. metadata +202 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 95877653a5a4ad8155f4e878171341e0c1d9ef6b43351fde6862504333900524
4
+ data.tar.gz: 26a8bafedb5064a49affa3fba245ffa8d02bc169c434d5b7ea3f9719f6a50188
5
+ SHA512:
6
+ metadata.gz: 70fabf7df1c3158c83a8a80f7fead2db93cd7679e0b6b333d9a157e094963709412f31773620eb7192cf36179666eee99e459da3140576f0476f1801eb3e161a
7
+ data.tar.gz: f1bb3cf40bbe51b1880c82093b179a0bf3d5be61ebaeaadbbc2bd91e2badee137cb3e88045b8896c796892fd8fe90b1d9e1a4dce495b91bae2a96050a87b38af
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ doc/
3
+ Gemfile.lock
4
+ coverage/
5
+ spec/rails_app/tmp/
6
+ spec/rails_app/log/
7
+ .ruby-version
8
+ /.bundle
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format doc
2
+ --color
@@ -0,0 +1,29 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Rails:
5
+ Enabled: true
6
+
7
+ Rails/HttpPositionalArguments:
8
+ Enabled: false
9
+
10
+ Bundler/OrderedGems:
11
+ Enabled: false
12
+
13
+ Style/FrozenStringLiteralComment:
14
+ Enabled: false
15
+
16
+ Style/Documentation:
17
+ Enabled: false
18
+
19
+ Layout/MultilineMethodCallIndentation:
20
+ Enabled: true
21
+ Exclude:
22
+ - 'spec/**/*'
23
+
24
+ Style/IndentArray:
25
+ Enabled: true
26
+ EnforcedStyle: consistent
27
+
28
+ Style/ModuleFunction:
29
+ Enabled: false
@@ -0,0 +1,20 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ script: bundle exec rspec
5
+
6
+ rvm:
7
+ - 2.5
8
+
9
+ before_install:
10
+ - npm install -g mjml
11
+
12
+ env:
13
+ matrix:
14
+ - RAILS_VERSION=5
15
+ - RAILS_VERSION=master
16
+
17
+ matrix:
18
+ fast_finish: true
19
+ allow_failures:
20
+ - env: RAILS_VERSION=master
@@ -0,0 +1,2 @@
1
+ # Changelog
2
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ rails_version = ENV.fetch('RAILS_VERSION', '5')
6
+
7
+ if rails_version == 'master'
8
+ git 'git://github.com/rails/rails.git' do
9
+ gem 'rails'
10
+ end
11
+ gem 'arel', github: 'rails/arel'
12
+ gem 'sprockets-rails', github: 'rails/sprockets-rails'
13
+ else
14
+ gem 'rails', "~> #{rails_version}"
15
+ end
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
202
+
@@ -0,0 +1,13 @@
1
+ run_env:
2
+ docker run \
3
+ -it \
4
+ --rm \
5
+ --name "$$(basename $$PWD)" \
6
+ -v `pwd`:/usr/src/app \
7
+ -w /usr/src/app \
8
+ starefossen/ruby-node:latest \
9
+ bash -c "bundle install && npm install -g mjml && bash"
10
+
11
+ publish:
12
+ gem build mjml-premailer
13
+ gem push
@@ -0,0 +1,98 @@
1
+ # mjml-premailer
2
+
3
+ Write your emails using [mjml framework](https://mjml.io) on rails, using any template language supported by Rails
4
+
5
+ [![Travis](https://travis-ci.org/srghma/mjml-premailer.svg?branch=master)](https://travis-ci.org/srghma/mjml-premailer)
6
+ [![GitHub version](https://badge.fury.io/gh/srghma%2Fmjml-premailer.svg)](https://badge.fury.io/gh/srghma%2Fmjml-premailer)
7
+ [![Maintainability](https://api.codeclimate.com/v1/badges/87ecd26fdfceb00dacb6/maintainability)](https://codeclimate.com/github/srghma/mjml-premailer/maintainability)
8
+ [![Coverage Status](https://coveralls.io/repos/github/srghma/mjml-premailer/badge.svg?branch=master)](https://coveralls.io/github/srghma/mjml-premailer?branch=master)
9
+
10
+ ## How it works
11
+ This gem will processes html part of your mail using `mjml` cli before delivery using rails ActionMailer hook
12
+
13
+ Or you can process it yourself using
14
+
15
+ ```ruby
16
+ MjmlPremailer::Hook.perform(mail)
17
+ ```
18
+
19
+ ## Installation
20
+
21
+ Install `mjml` npm package (v4) globally
22
+
23
+ ```sh
24
+ $ npm install -g mjml@^4.0
25
+ ```
26
+
27
+ or locally
28
+
29
+ ```sh
30
+ $ npm install --save-dev mjml@^4.0
31
+ ```
32
+
33
+ Add the gem to your `Gemfile`:
34
+
35
+ ```ruby
36
+ gem 'mjml-premailer'
37
+ ```
38
+
39
+ ## Configuration options
40
+
41
+ In `/config/initializers/mjml_premailer.rb`
42
+
43
+ ```ruby
44
+ MjmlPremailer.config.merge!(
45
+ bin: ..., # by default found authomatically
46
+ debug: false, # true/false
47
+ beautify: true, # true/false
48
+ minify: false, # true/false
49
+ keep_comments: false, # true/false
50
+ validation_level: :skip # :strict/:soft/:skip
51
+ )
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ```erb
57
+ <!-- app/views/layouts/mailer.html.erb -->
58
+
59
+ <mjml>
60
+ <mj-body>
61
+ <%= yield %>
62
+ <mj-body>
63
+ </mjml>
64
+ ```
65
+
66
+
67
+ ```erb
68
+ <!-- app/views/welcome_mailer/welcome.html.erb -->
69
+
70
+ <mj-text>Hello, <%= @user.name %></mj-text>
71
+
72
+ ```
73
+
74
+ ```
75
+ class WelcomeMailer < ApplicationMailer
76
+ def welcome(user)
77
+ @user = user
78
+ mail(to: @user.email, subject: 'Welcome')
79
+ end
80
+ end
81
+ ```
82
+
83
+ Example rails project you can find [here](example)
84
+
85
+ Mjml documentation is [here](https://mjml.io/documentation)
86
+
87
+
88
+ ## Difference from other gems
89
+
90
+ [sighmon/mjml-rails](https://github.com/sighmon/mjml-rails):
91
+ - outdated
92
+ - work on hacks
93
+ - no support for `/app/views/layouts`
94
+
95
+ [kolybasov/mjml-ruby](https://github.com/kolybasov/mjml-ruby/):
96
+ - best gem I found, this gem is based on it, thanks [kolybasov](https://github.com/kolybasov) for his work
97
+ - doesnt support mjml v4 (at time of writing)
98
+ - doesnt support template languages other then erb (at least I didnt managed)
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,16 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+ /db/*.sqlite3-journal
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*.log
16
+ /tmp
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'mjml-premailer', path: '..'
4
+ gem 'nokogiri'
5
+ gem 'rails', '~> 5.0'
6
+
7
+ platforms :rbx do
8
+ gem 'racc'
9
+ gem 'rubysl'
10
+ end
@@ -0,0 +1,10 @@
1
+ # Example Rails App
2
+
3
+ To run this app, run:
4
+
5
+ ```shell
6
+ bundle
7
+ bundle exec rails s
8
+ ```
9
+
10
+ Then point your browser at [http://localhost:3000/](http://localhost:3000/).
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,32 @@
1
+ body {
2
+ background: #efefef;
3
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
4
+ }
5
+
6
+ p {
7
+ line-height: 1.4;
8
+ }
9
+
10
+ .wrap {
11
+ max-width: 40em;
12
+ margin: 0 auto;
13
+ padding: 1em;
14
+ background: white;
15
+ }
16
+
17
+ .greeting {
18
+ text-align: center;
19
+ font-weight: bold;
20
+ font-size: 110%;
21
+ }
22
+
23
+ .footer {
24
+ font-size: 90%;
25
+ color: #666;
26
+ }
27
+
28
+ a {
29
+ color: green;
30
+ text-decoration: none;
31
+ border-bottom: 2px solid green;
32
+ }
@@ -0,0 +1,9 @@
1
+ class ExampleMailer < ActionMailer::Base
2
+ default from: "from@example.com"
3
+
4
+ layout 'mail'
5
+
6
+ def test_message
7
+ mail to: 'to@example.org', subject: 'Test Message'
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ <mj-text>Hello from wrapper</mj-text>
2
+
3
+ <%= yield %>
@@ -0,0 +1,9 @@
1
+ <mj-section>
2
+ <mj-column>
3
+ <mj-text>Hello from test_message outside block</mj-text>
4
+
5
+ <%= render 'wrapper' do %>
6
+ <mj-text>Hello from test_message inside block</mj-text>
7
+ <% end %>
8
+ </mj-column>
9
+ </mj-section>
@@ -0,0 +1,7 @@
1
+ <mjml>
2
+ <mj-body>
3
+ <mj-text>Hello from layout</mj-text>
4
+
5
+ <%= yield %>
6
+ </mj-body>
7
+ </mjml>
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Rails.application
@@ -0,0 +1,12 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require 'action_controller/railtie'
4
+ require 'action_mailer/railtie'
5
+ require 'sprockets/railtie'
6
+
7
+ Bundler.require(*Rails.groups)
8
+
9
+ module Example
10
+ class Application < Rails::Application
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2
+
3
+ require 'bundler/setup' # Set up gems listed in the Gemfile.
@@ -0,0 +1,5 @@
1
+ # Load the Rails application.
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the Rails application.
5
+ Rails.application.initialize!
@@ -0,0 +1,9 @@
1
+ Rails.application.configure do
2
+ config.cache_classes = false
3
+ config.eager_load = false
4
+ config.consider_all_requests_local = true
5
+ config.action_controller.perform_caching = false
6
+ config.assets.debug = true
7
+ config.assets.digest = true
8
+ config.assets.raise_runtime_errors = true
9
+ end
@@ -0,0 +1,9 @@
1
+ Rails.application.configure do
2
+ config.cache_classes = true
3
+ config.eager_load = true
4
+ config.consider_all_requests_local = false
5
+ config.action_controller.perform_caching = true
6
+ config.assets.compile = false
7
+ config.assets.digest = true
8
+ config.log_level = :info
9
+ end
@@ -0,0 +1,2 @@
1
+ Rails.application.config.assets.version = '1.0'
2
+ Rails.application.config.assets.precompile += %w( email.css )
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ root to: redirect('rails/mailers/example_mailer/test_message')
3
+ end
@@ -0,0 +1,2 @@
1
+ development:
2
+ secret_key_base: bc1d05753b1a42a7d983dcb4f998c433532ec8f91ab3842a36ed3d9072d143a2d9c05a6dc43a3d780a2ff3d8e7b75a1011ae2e0d13a022e98dc1f0299da5a5a0
@@ -0,0 +1,5 @@
1
+ class ExampleMailerPreview < ActionMailer::Preview
2
+ def test_message
3
+ ExampleMailer.test_message
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ require 'action_mailer'
2
+
3
+ require 'mjml-premailer/version'
4
+ require 'mjml-premailer/hook'
5
+ require 'mjml-premailer/find_executable'
6
+
7
+ class MjmlPremailer
8
+ # from https://github.com/kolybasov/mjml-ruby/blob/master/lib/mjml.rb#L33
9
+ @config = {
10
+ bin: MjmlPremailer::FindExecutable.find_executable,
11
+ debug: false,
12
+ beautify: true,
13
+ minify: false,
14
+ keep_comments: false,
15
+ validation_level: :skip # :strict/:soft/:skip
16
+ }
17
+
18
+ class << self
19
+ attr_accessor :config
20
+ end
21
+
22
+ def self.register_interceptors
23
+ ActionMailer::Base.register_interceptor(MjmlPremailer::Hook)
24
+
25
+ if ActionMailer::Base.respond_to?(:register_preview_interceptor)
26
+ ActionMailer::Base.register_preview_interceptor(MjmlPremailer::Hook)
27
+ end
28
+ end
29
+ end
30
+
31
+ require 'mjml-premailer/railtie' if defined?(Rails)
@@ -0,0 +1,11 @@
1
+ class MjmlPremailer
2
+ module FindExecutable
3
+ extend self
4
+
5
+ def find_executable
6
+ local_path = File.expand_path('node_modules/.bin/mjml', Dir.pwd)
7
+ return local_path if File.file?(local_path)
8
+ `/usr/bin/env bash -c "which mjml"`.strip
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,97 @@
1
+ require 'open3'
2
+
3
+ class MjmlPremailer
4
+ module Hook
5
+ extend self
6
+
7
+ def perform(mail)
8
+ html_part = mail.html_part || mail
9
+ html = html_part.body.to_s
10
+
11
+ debug '> MjmlPremailer template:'
12
+ debug html
13
+
14
+ parsed_html, error = parse(html)
15
+
16
+ error_ = error.strip.presence
17
+
18
+ raise error_ if error_
19
+
20
+ debug '> MjmlPremailer parsed template:'
21
+ debug parsed_html
22
+
23
+ html_part.body = parsed_html
24
+ end
25
+
26
+ alias delivering_email perform
27
+ alias previewing_email perform
28
+
29
+ private
30
+
31
+ def parse(html_body)
32
+ bin = MjmlPremailer.config[:bin]
33
+
34
+ beautify = MjmlPremailer.config[:beautify]
35
+ beautify_option = "--config.beautify #{beautify}"
36
+
37
+ minify = MjmlPremailer.config[:minify]
38
+ minify_option = "--config.minify #{minify}"
39
+
40
+ keep_comments = MjmlPremailer.config[:keep_comments]
41
+ keep_comments_option = "--config.keepComments #{keep_comments}"
42
+
43
+ validation_level = MjmlPremailer.config[:validation_level]
44
+ validation_level_option = "--config.validationLevel #{validation_level}"
45
+
46
+ read_input_to_stdin_option = '-i'
47
+
48
+ # stolen from https://github.com/kolybasov/mjml-ruby/blob/master/lib/mjml/parser.rb
49
+ should_get_outpout_from_file = html_body.size > 20_000
50
+
51
+ if should_get_outpout_from_file
52
+ temp_file = Tempfile.new
53
+
54
+ write_output_to_tempfile_option = "-o #{temp_file.path}"
55
+
56
+ cmd = [
57
+ bin,
58
+ read_input_to_stdin_option,
59
+ write_output_to_tempfile_option,
60
+ beautify_option,
61
+ minify_option,
62
+ keep_comments_option,
63
+ validation_level_option
64
+ ].join(' ')
65
+
66
+ _out, err, _sts = Open3.capture3(cmd, stdin_data: html_body)
67
+
68
+ temp_file.rewind
69
+ temp_file.unlink
70
+
71
+ [temp_file.read, err]
72
+ else
73
+ write_output_to_stdout_option = '-s'
74
+
75
+ cmd = [
76
+ bin,
77
+ read_input_to_stdin_option,
78
+ write_output_to_stdout_option,
79
+ beautify_option,
80
+ minify_option,
81
+ keep_comments_option,
82
+ validation_level_option
83
+ ].join(' ')
84
+
85
+ debug "> MjmlPremailer command: #{cmd}"
86
+
87
+ out, err, _sts = Open3.capture3(cmd, stdin_data: html_body)
88
+
89
+ [out, err]
90
+ end
91
+ end
92
+
93
+ def debug(str)
94
+ puts str if MjmlPremailer.config[:debug]
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,7 @@
1
+ class MjmlPremailer
2
+ class Railtie < ::Rails::Railtie
3
+ config.after_initialize do
4
+ ::MjmlPremailer.register_interceptors
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class MjmlPremailer
2
+ VERSION = File.read(
3
+ File.expand_path('../../VERSION', __dir__)
4
+ ).strip
5
+ end
@@ -0,0 +1,26 @@
1
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
2
+ require 'mjml-premailer/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'mjml-premailer'
6
+ s.version = MjmlPremailer::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.license = 'Apache-2.0'
9
+ s.authors = ['Sergey Homa']
10
+ s.email = ['srghma@gmail.com']
11
+ s.homepage = 'https://github.com/srghma/mjml-premailer'
12
+ s.summary = 'Write your emails using mjml framework'
13
+ s.description = 'This gem will processes html part of your mail using `mjml` cli before delivery using rails ActionMailer hook'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {example,spec}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_dependency 'actionmailer'
21
+
22
+ s.add_development_dependency 'coveralls' if RUBY_ENGINE == 'ruby'
23
+ s.add_development_dependency 'nokogiri'
24
+ s.add_development_dependency 'pry'
25
+ s.add_development_dependency 'rspec', '~> 3.3'
26
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActionMailer::Base delivery' do
4
+ it 'delivers email with inlined CSS' do
5
+ custom_greeting = 'Custom greeting'
6
+ WelcomeMailer.welcome_email(custom_greeting).deliver_now
7
+
8
+ mail = ActionMailer::Base.deliveries.last
9
+ expect(mail).to be_present
10
+
11
+ html_part = mail.html_part || mail
12
+ html = html_part.body.to_s
13
+
14
+ expect(html).to be_present
15
+
16
+ # expect(html).to start_with?('<!doctype')
17
+ expect(html).to include(custom_greeting)
18
+ expect(html).to include(%(Hello from test_message outside block))
19
+ expect(html).to include(%(Hello from test_message inside block))
20
+ expect(html).to include(%(Hello from wrapper))
21
+ expect(html).to include(%(Hello from layout))
22
+
23
+ expect(html).not_to include(%(mj-text))
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: 'from@example.com'
3
+ layout 'mail'
4
+ end
@@ -0,0 +1,6 @@
1
+ class WelcomeMailer < ApplicationMailer
2
+ def welcome_email(greeting)
3
+ @greeting = greeting
4
+ mail to: 'example@example.com'
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ <mjml>
2
+ <mj-body>
3
+ <mj-text>Hello from layout</mj-text>
4
+
5
+ <%= yield %>
6
+ </mj-body>
7
+ </mjml>
@@ -0,0 +1,3 @@
1
+ <mj-text>Hello from wrapper</mj-text>
2
+
3
+ <%= yield %>
@@ -0,0 +1,11 @@
1
+ <mj-section>
2
+ <mj-column>
3
+ <mj-text><%= @greeting %></mj-text>
4
+
5
+ <mj-text>Hello from test_message outside block</mj-text>
6
+
7
+ <%= render 'wrapper' do %>
8
+ <mj-text>Hello from test_message inside block</mj-text>
9
+ <% end %>
10
+ </mj-column>
11
+ </mj-section>
@@ -0,0 +1,5 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require_relative 'config/environment'
4
+
5
+ run Rails.application
@@ -0,0 +1,13 @@
1
+ require_relative 'boot'
2
+
3
+ require "action_mailer/railtie"
4
+ require "action_view/railtie"
5
+ require "sprockets/railtie"
6
+ require "rails/test_unit/railtie"
7
+
8
+ Bundler.require(*Rails.groups)
9
+
10
+ module Dummy
11
+ class Application < Rails::Application
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -0,0 +1,2 @@
1
+ require_relative 'application'
2
+ Rails.application.initialize!
@@ -0,0 +1,10 @@
1
+ Rails.application.configure do
2
+ config.cache_classes = true
3
+ config.eager_load = false
4
+ config.consider_all_requests_local = true
5
+ config.action_controller.perform_caching = false
6
+ config.action_dispatch.show_exceptions = false
7
+ config.action_controller.allow_forgery_protection = false
8
+ config.action_mailer.delivery_method = :test
9
+ config.active_support.deprecation = :stderr
10
+ end
@@ -0,0 +1 @@
1
+ Rails.application.config.assets.version = '1.0'
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ root 'application#main'
3
+ end
@@ -0,0 +1,18 @@
1
+ if RUBY_ENGINE == 'ruby'
2
+ if ENV['CI']
3
+ require 'coveralls'
4
+ Coveralls::Output.silent = true
5
+ Coveralls.wear! do
6
+ add_filter 'spec/'
7
+ end
8
+ else
9
+ require 'simplecov'
10
+ SimpleCov.start
11
+ end
12
+ end
13
+
14
+ # Configure Rails Environment
15
+ ENV["RAILS_ENV"] = "test"
16
+ require File.expand_path("../../spec/rails_app/config/environment.rb", __FILE__)
17
+
18
+ require 'nokogiri'
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe MjmlPremailer do
4
+ describe '#config' do
5
+ subject { MjmlPremailer.config }
6
+ context 'when set' do
7
+ around do |example|
8
+ begin
9
+ default_config = described_class.config
10
+ described_class.config = { foo: :bar }
11
+ example.run
12
+ ensure
13
+ described_class.config = default_config
14
+ end
15
+ end
16
+
17
+ it { is_expected.to eq(foo: :bar) }
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mjml-premailer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sergey Homa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionmailer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coveralls
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.3'
83
+ description: This gem will processes html part of your mail using `mjml` cli before
84
+ delivery using rails ActionMailer hook
85
+ email:
86
+ - srghma@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".coveralls.yml"
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - ".rubocop.yml"
95
+ - ".travis.yml"
96
+ - CHANGELOG.md
97
+ - Gemfile
98
+ - LICENSE
99
+ - Makefile
100
+ - README.md
101
+ - Rakefile
102
+ - VERSION
103
+ - example/.gitignore
104
+ - example/Gemfile
105
+ - example/README.md
106
+ - example/Rakefile
107
+ - example/app/assets/stylesheets/email.css
108
+ - example/app/mailers/example_mailer.rb
109
+ - example/app/views/example_mailer/_wrapper.html.erb
110
+ - example/app/views/example_mailer/test_message.html.erb
111
+ - example/app/views/layout/mail.html.erb
112
+ - example/bin/rails
113
+ - example/config.ru
114
+ - example/config/application.rb
115
+ - example/config/boot.rb
116
+ - example/config/environment.rb
117
+ - example/config/environments/development.rb
118
+ - example/config/environments/production.rb
119
+ - example/config/initializers/assets.rb
120
+ - example/config/routes.rb
121
+ - example/config/secrets.yml
122
+ - example/test/mailers/previews/example_mailer_preview.rb
123
+ - lib/mjml-premailer.rb
124
+ - lib/mjml-premailer/find_executable.rb
125
+ - lib/mjml-premailer/hook.rb
126
+ - lib/mjml-premailer/railtie.rb
127
+ - lib/mjml-premailer/version.rb
128
+ - mjml-premailer.gemspec
129
+ - spec/integration/delivery_spec.rb
130
+ - spec/rails_app/app/mailers/application_mailer.rb
131
+ - spec/rails_app/app/mailers/welcome_mailer.rb
132
+ - spec/rails_app/app/views/layouts/mail.html.erb
133
+ - spec/rails_app/app/views/welcome_mailer/_wrapper.html.erb
134
+ - spec/rails_app/app/views/welcome_mailer/welcome_email.html.erb
135
+ - spec/rails_app/config.ru
136
+ - spec/rails_app/config/application.rb
137
+ - spec/rails_app/config/boot.rb
138
+ - spec/rails_app/config/environment.rb
139
+ - spec/rails_app/config/environments/test.rb
140
+ - spec/rails_app/config/initializers/assets.rb
141
+ - spec/rails_app/config/routes.rb
142
+ - spec/spec_helper.rb
143
+ - spec/unit/config_spec.rb
144
+ homepage: https://github.com/srghma/mjml-premailer
145
+ licenses:
146
+ - Apache-2.0
147
+ metadata: {}
148
+ post_install_message:
149
+ rdoc_options: []
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ requirements: []
163
+ rubyforge_project:
164
+ rubygems_version: 2.7.6
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: Write your emails using mjml framework
168
+ test_files:
169
+ - example/Gemfile
170
+ - example/README.md
171
+ - example/Rakefile
172
+ - example/app/assets/stylesheets/email.css
173
+ - example/app/mailers/example_mailer.rb
174
+ - example/app/views/example_mailer/_wrapper.html.erb
175
+ - example/app/views/example_mailer/test_message.html.erb
176
+ - example/app/views/layout/mail.html.erb
177
+ - example/bin/rails
178
+ - example/config.ru
179
+ - example/config/application.rb
180
+ - example/config/boot.rb
181
+ - example/config/environment.rb
182
+ - example/config/environments/development.rb
183
+ - example/config/environments/production.rb
184
+ - example/config/initializers/assets.rb
185
+ - example/config/routes.rb
186
+ - example/config/secrets.yml
187
+ - example/test/mailers/previews/example_mailer_preview.rb
188
+ - spec/integration/delivery_spec.rb
189
+ - spec/rails_app/app/mailers/application_mailer.rb
190
+ - spec/rails_app/app/mailers/welcome_mailer.rb
191
+ - spec/rails_app/app/views/layouts/mail.html.erb
192
+ - spec/rails_app/app/views/welcome_mailer/_wrapper.html.erb
193
+ - spec/rails_app/app/views/welcome_mailer/welcome_email.html.erb
194
+ - spec/rails_app/config.ru
195
+ - spec/rails_app/config/application.rb
196
+ - spec/rails_app/config/boot.rb
197
+ - spec/rails_app/config/environment.rb
198
+ - spec/rails_app/config/environments/test.rb
199
+ - spec/rails_app/config/initializers/assets.rb
200
+ - spec/rails_app/config/routes.rb
201
+ - spec/spec_helper.rb
202
+ - spec/unit/config_spec.rb