├── .github ├── FUNDING.yml └── workflows │ └── test.yml ├── .gitignore ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── Guardfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── archive ├── mjml-rails-2.1.1.gem ├── mjml-rails-2.1.1.gem.sha512 ├── mjml-rails-2.1.4.1.gem ├── mjml-rails-2.1.4.1.gem.sha512 ├── mjml-rails-2.1.4.gem ├── mjml-rails-2.1.4.gem.sha512 ├── mjml-rails-2.2.0.gem ├── mjml-rails-2.2.0.gem.sha512 ├── mjml-rails-2.3.0.gem ├── mjml-rails-2.3.0.gem.sha512 ├── mjml-rails-2.3.1.gem ├── mjml-rails-2.3.1.gem.sha512 ├── mjml-rails-2.4.0.gem ├── mjml-rails-2.4.0.gem.sha512 ├── mjml-rails-2.4.1.gem ├── mjml-rails-2.4.1.gem.sha512 ├── mjml-rails-2.4.2.gem ├── mjml-rails-2.4.2.gem.sha512 ├── mjml-rails-2.4.3.gem ├── mjml-rails-2.4.3.gem.sha512 ├── mjml-rails-4.0.0.gem ├── mjml-rails-4.0.0.gem.sha512 ├── mjml-rails-4.0.1.gem ├── mjml-rails-4.0.1.gem.sha512 ├── mjml-rails-4.0.2.gem ├── mjml-rails-4.0.2.gem.sha512 ├── mjml-rails-4.0.3.gem ├── mjml-rails-4.0.3.gem.sha512 ├── mjml-rails-4.1.0.gem ├── mjml-rails-4.1.0.gem.sha512 ├── mjml-rails-4.10.0.gem ├── mjml-rails-4.10.0.gem.sha512 ├── mjml-rails-4.10.1.gem ├── mjml-rails-4.10.1.gem.sha512 ├── mjml-rails-4.11.0.gem ├── mjml-rails-4.11.0.gem.sha512 ├── mjml-rails-4.12.0.gem ├── mjml-rails-4.12.0.gem.sha512 ├── mjml-rails-4.12.1.gem ├── mjml-rails-4.12.1.gem.sha512 ├── mjml-rails-4.13.0.gem ├── mjml-rails-4.13.0.gem.sha512 ├── mjml-rails-4.14.0.gem ├── mjml-rails-4.14.0.gem.sha512 ├── mjml-rails-4.14.1.gem ├── mjml-rails-4.14.1.gem.sha512 ├── mjml-rails-4.15.0.gem ├── mjml-rails-4.15.0.gem.sha512 ├── mjml-rails-4.2.0.gem ├── mjml-rails-4.2.0.gem.sha512 ├── mjml-rails-4.2.1.gem ├── mjml-rails-4.2.1.gem.sha512 ├── mjml-rails-4.2.2.gem ├── mjml-rails-4.2.2.gem.sha512 ├── mjml-rails-4.2.3.gem ├── mjml-rails-4.2.3.gem.sha512 ├── mjml-rails-4.2.4.gem ├── mjml-rails-4.2.4.gem.sha512 ├── mjml-rails-4.2.5.gem ├── mjml-rails-4.2.5.gem.sha512 ├── mjml-rails-4.3.0.gem ├── mjml-rails-4.3.0.gem.sha512 ├── mjml-rails-4.3.1.gem ├── mjml-rails-4.3.1.gem.sha512 ├── mjml-rails-4.3.2.gem ├── mjml-rails-4.3.2.gem.sha512 ├── mjml-rails-4.4.0.gem ├── mjml-rails-4.4.0.gem.sha512 ├── mjml-rails-4.4.1.gem ├── mjml-rails-4.4.1.gem.sha512 ├── mjml-rails-4.4.2.gem ├── mjml-rails-4.4.2.gem.sha512 ├── mjml-rails-4.5.0.gem ├── mjml-rails-4.5.0.gem.sha512 ├── mjml-rails-4.6.0.gem ├── mjml-rails-4.6.0.gem.sha512 ├── mjml-rails-4.6.1.gem ├── mjml-rails-4.6.1.gem.sha512 ├── mjml-rails-4.7.0.gem ├── mjml-rails-4.7.0.gem.sha512 ├── mjml-rails-4.7.1.gem ├── mjml-rails-4.7.1.gem.sha512 ├── mjml-rails-4.7.2.gem ├── mjml-rails-4.7.2.gem.sha512 ├── mjml-rails-4.8.0.gem ├── mjml-rails-4.8.0.gem.sha512 ├── mjml-rails-4.9.0.gem └── mjml-rails-4.9.0.gem.sha512 ├── certs └── sighmon.pem ├── lib ├── generators │ └── mjml │ │ ├── install │ │ ├── install_generator.rb │ │ └── templates │ │ │ └── mjml.rb │ │ └── mailer │ │ ├── mailer_generator.rb │ │ └── templates │ │ ├── layout.html.mjml │ │ └── view.html.erb ├── mjml-rails.rb ├── mjml.rb └── mjml │ ├── cache.rb │ ├── handler.rb │ ├── mrml_parser.rb │ ├── parser.rb │ ├── railtie.rb │ └── version.rb ├── mjml-rails-4.15.1.gem ├── mjml-rails-4.15.1.gem.sha512 ├── mjml-rails.gemspec └── test ├── fixtures └── valid-mjml-binary │ └── empty-path │ └── which ├── generator_test.rb ├── mjml_test.rb ├── mrml_parser_test.rb ├── parser_test.rb ├── test_helper.rb └── views ├── layouts ├── _email_tracking_code.ruby ├── default.html.mjml └── default.text.ruby ├── no_layout_mailer ├── _user_header.mjml ├── inform_contact.mjml └── with_owa.mjml ├── notifier_mailer ├── _user_header.html.erb ├── inform_contact.html.erb ├── inform_contact.text ├── invalid_template.html.erb └── invalid_template.text └── test_template.mjml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [sighmon] 4 | ko_fi: sighmon 5 | 6 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: test 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | package_manager: 14 | - npm 15 | - yarn 16 | - bun 17 | rails_version: 18 | - "~> 8.0" 19 | - "~> 7.2" 20 | - "~> 7.1" 21 | - "~> 7.0" 22 | ruby_version: 23 | - "3.3" 24 | - "3.2" 25 | - "3.1" 26 | exclude: 27 | - rails_version: "~> 8.0" 28 | ruby_version: "3.1" 29 | name: ${{ matrix.package_manager }}, Rails ${{ matrix.rails_version }}, Ruby ${{ matrix.ruby_version }} 30 | 31 | steps: 32 | - uses: actions/checkout@v3 33 | - name: Set up Ruby 34 | uses: ruby/setup-ruby@v1 35 | with: 36 | ruby-version: ${{ matrix.ruby_version }} 37 | - name: Install Bundler 2.4 for Ruby 2.7 38 | if: matrix.ruby_version == '2.7' 39 | run: gem install bundler -v 2.4 40 | - name: Set up Node 41 | uses: actions/setup-node@v3 42 | if: ${{ contains(fromJSON('["npm", "yarn"]'), matrix.package_manager) }} 43 | with: 44 | node-version: "22" 45 | - name: Set up Bun 46 | uses: oven-sh/setup-bun@v2 47 | if: ${{ matrix.package_manager == 'bun' }} 48 | with: 49 | bun-version: 1.1.42 50 | - name: Install rails dependencies 51 | env: 52 | RAILS_VERSION: ${{ matrix.rails_version }} 53 | run: | 54 | if [ "${{ matrix.ruby_version }}" = "2.7" ]; then 55 | bundle _2.4_ install --jobs 4 --retry 3 56 | else 57 | bundle install --jobs 4 --retry 3 58 | fi 59 | - name: Install mjml with npm 60 | if: ${{ matrix.package_manager == 'npm' }} 61 | run: npm add mjml 62 | - name: Install mjml with yarn 63 | if: ${{ matrix.package_manager == 'yarn' }} 64 | run: yarn add mjml 65 | - name: Install mjml with bun 66 | if: ${{ matrix.package_manager == 'bun' }} 67 | run: bun add mjml 68 | - name: Run tests 69 | env: 70 | RAILS_VERSION: ${{ matrix.rails_version }} 71 | run: rake 72 | - name: Run RuboCop 73 | run: bundle exec rubocop 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | .bundle 3 | test/tmp 4 | 00* 5 | *.sublime-* 6 | node_modules 7 | .byebug_history 8 | 9 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | require: 2 | - rubocop-performance 3 | - rubocop-rails 4 | AllCops: 5 | TargetRubyVersion: 2.5 6 | DisplayCopNames: true 7 | NewCops: enable 8 | 9 | Metrics/ModuleLength: 10 | Max: 120 11 | Metrics/BlockLength: 12 | IgnoredMethods: 13 | - describe 14 | - guard 15 | Rails/ApplicationMailer: 16 | Enabled: false 17 | Rails/Output: 18 | Enabled: false 19 | Style/Documentation: 20 | Enabled: false 21 | Style/FrozenStringLiteralComment: 22 | Exclude: 23 | - 'test/**/views/**/*.ruby' 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 4.15.1 2 | 3 | * Robert Keresnyei fixed MRML after template caching broke it. 4 | 5 | ## 4.15.0 6 | 7 | * Nima Yonten added template caching. 8 | 9 | ## 4.14.1 10 | 11 | * Tom Naessens prioritised mrml binary check to avoid mjml binary check warnings. 12 | 13 | ## 4.14.0 14 | 15 | * Emi added Windows support. 16 | 17 | ## 4.13.0 18 | 19 | * Noel Blaschke added support for Bun without Node.js 20 | 21 | ## 4.12.1 22 | 23 | * Paul Hinze fixed a stray stderr output on machines with GNU which. 24 | 25 | ## 4.12.0 26 | 27 | * Ray Brown added support for the Bun package manager. 28 | 29 | ## 4.11.0 30 | 31 | * Claire Zuliani added config settings for MJML fonts. 32 | 33 | ## 4.10.1 34 | 35 | * Fixed the binary check when using MRML to avoid warnings. 36 | 37 | ## 4.10.0 38 | 39 | * Pokonski added support for MRML which is a fast Rust implementation of MJML. 40 | 41 | ## 4.9.0 42 | 43 | * Yuta Hayashi added support for Yarn 2. 44 | 45 | ## 4.8.0 46 | 47 | * Alan Halatian updated the MJML binary discovery when installed with Yarn. 48 | 49 | ## 4.7.2 50 | 51 | * Florian Dütsch added the Node process exit code when the parser raises a ParseError. 52 | 53 | ## 4.7.1 54 | 55 | * Florian Dütsch fixed a bug where Mjml::Parser#render suppresses errors in case of Tempfile exceptions. 56 | 57 | ## 4.7.0 58 | 59 | * Florian Dütsch added RuboCop integration. 60 | 61 | ## 4.6.1 62 | 63 | * doits simplified the MJML Handler class and regex, so rendering should be faster. 64 | 65 | ## 4.6.0 66 | 67 | * doits added custom MJML binary location configuration via mjml_binary setting. 68 | 69 | ## 4.5.0 70 | 71 | * **Note**: default validation level is now *strict*. 72 | * doits fixed MJML-Rails validation level to match MJML validation. 73 | * haffla fixed the post-install message. 74 | 75 | ## 4.4.2 76 | 77 | * Implement denny's fix to detect MJML template errors. 78 | 79 | ## 4.4.1 80 | 81 | * doits refactored discovery of the MJML binary. 82 | 83 | ## 4.4.0 84 | 85 | * zeh235 added support for setting the MJML validationLevel. 86 | 87 | ## 4.3.2 88 | 89 | * adrianob fixed discovering the npm/yarn bin path using Open3 instead of back ticks. 90 | 91 | ## 4.3.1 92 | 93 | * Jan Sandbrink fixed discovering MJML binary, when only yarn, but not npm is installed. 94 | 95 | ## 4.3.0 96 | 97 | * Paul Mucur added better path escaping on the IO.popen command. Markus Doits added Rails 6 support by adding the optional second source parameter to template handler calls. 98 | 99 | ## 4.2.5 100 | 101 | * Stephan Biastoch added rendering errors to true by default - see pull request #37. 102 | 103 | ## 4.2.4 104 | 105 | * Mandy Huang added config settings for MJML beautify and minify. 106 | 107 | ## 4.2.3 108 | 109 | * Patrick Bougie and Daniel suggested a fix to enable alternative binary support - see #39. Also updated for MJML 4.2.0 110 | 111 | ## 4.2.2 112 | 113 | * Patrick Bougie fixed a bug where an expanded MJML root tag resulted in the message not rendering to HTML. 114 | 115 | ## 4.2.1 116 | 117 | * Implemented Aleksandrs Ļedovskis' fix for Haml/Slim layouts. 118 | 119 | ## 4.2.0 120 | 121 | * Aleksandrs Ļedovskis refactored MJML layout/template support to better match Rails standards. 122 | 123 | ## 4.1.0 124 | 125 | * Ryan Ahearn updated for 4.1.0 and improved Tempfile usage. 126 | 127 | ## 4.0.3 128 | 129 | * Anh Tran added the use of Open3.popen3 to support error raising for Mjml::Parse#run method. 130 | 131 | ## 4.0.2 132 | 133 | * Max Mulatz, 🧟‍ squisher. Fixed a zombie process from the version checker (also cutest pull-request 🏆). 134 | 135 | ## 4.0.1 136 | 137 | * Option to raise render errors added to the config by Anh Tran. 138 | 139 | ## 4.0.0 140 | 141 | * Updated for MJML v4.0.0 thanks to JP Boily. 142 | 143 | ## 2.4.3 144 | 145 | * Checks if Yarn is installed for webpacker users. 146 | 147 | ## 2.4.2 148 | 149 | * Only raise error when really using mjml if binary is not found. 150 | 151 | ## 2.4.1 152 | 153 | * Using IO.popen from tylerhunt's branch to check if the MJML binary is installed. 154 | 155 | ## 2.3.0 156 | 157 | * Updated to support HAML and other template languages. 158 | 159 | ## 2.2.0 160 | 161 | * Updated to work with MJML v2.x 162 | * Performing executable checks and version checks at initialize time. 163 | 164 | ## 2.1.4.1 165 | 166 | * Removing require: 'mjml' from the Gemfile install line. 167 | 168 | ## 2.1.4 169 | 170 | * Updated to MJML v2.1.4 171 | 172 | ## 2.1.1 173 | 174 | * Supports new tags in MJML v2.1.1 175 | * Version number now matches MJML.io version 176 | 177 | ## 1.0.0 178 | 179 | * First release. 180 | * Supports MJML 1.x 181 | * Allows use of ERb in templates 182 | * Allows use of partials in templates 183 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | gemspec 5 | gem 'rails', ENV['RAILS_VERSION'] if ENV['RAILS_VERSION'] 6 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # A sample Guardfile 4 | # More info at https://github.com/guard/guard#readme 5 | 6 | ## Uncomment and set this to only include directories you want to watch 7 | # directories %w(app lib config test spec features) \ 8 | # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")} 9 | 10 | ## Note: if you are using the `directories` clause above and you are not 11 | ## watching the project directory ('.'), then you will want to move 12 | ## the Guardfile to a watched dir and symlink it back, e.g. 13 | # 14 | # $ mkdir config 15 | # $ mv Guardfile config/ 16 | # $ ln -s config/Guardfile . 17 | # 18 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile" 19 | 20 | guard :minitest do 21 | # with Minitest::Unit 22 | # watch(%r{^test/(.*)\/?test_(.*)\.rb$}) 23 | # watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" } 24 | # watch(%r{^test/test_helper\.rb$}) { 'test' } 25 | 26 | # with Minitest::Spec 27 | # watch(%r{^spec/(.*)_spec\.rb$}) 28 | # watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 29 | # watch(%r{^spec/spec_helper\.rb$}) { 'spec' } 30 | 31 | # Rails 4 32 | watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" } 33 | watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' } 34 | watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" } 35 | watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" } 36 | watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" } 37 | watch(%r{^test/.+_test\.rb$}) 38 | watch(%r{^test/test_helper\.rb$}) { 'test' } 39 | 40 | # Rails < 4 41 | # watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" } 42 | # watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" } 43 | # watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" } 44 | end 45 | 46 | # NOTE: The cmd option is now required due to the increasing number of ways 47 | # rspec may be run, below are examples of the most common uses. 48 | # * bundler: 'bundle exec rspec' 49 | # * bundler binstubs: 'bin/rspec' 50 | # * spring: 'bin/rspec' (This will use spring if running and you have 51 | # installed the spring binstubs per the docs) 52 | # * zeus: 'zeus rspec' (requires the server to be started separately) 53 | # * 'just' rspec: 'rspec' 54 | 55 | guard :rspec, cmd: 'bundle exec rspec' do 56 | require 'guard/rspec/dsl' 57 | dsl = Guard::RSpec::Dsl.new(self) 58 | 59 | # Feel free to open issues for suggestions and improvements 60 | 61 | # RSpec files 62 | rspec = dsl.rspec 63 | watch(rspec.spec_helper) { rspec.spec_dir } 64 | watch(rspec.spec_support) { rspec.spec_dir } 65 | watch(rspec.spec_files) 66 | 67 | # Ruby files 68 | ruby = dsl.ruby 69 | dsl.watch_spec_files_for(ruby.lib_files) 70 | 71 | # Rails files 72 | rails = dsl.rails(view_extensions: %w[erb haml slim]) 73 | dsl.watch_spec_files_for(rails.app_files) 74 | dsl.watch_spec_files_for(rails.views) 75 | 76 | watch(rails.controllers) do |m| 77 | [ 78 | rspec.spec.call("routing/#{m[1]}_routing"), 79 | rspec.spec.call("controllers/#{m[1]}_controller"), 80 | rspec.spec.call("acceptance/#{m[1]}") 81 | ] 82 | end 83 | 84 | # Rails config changes 85 | watch(rails.spec_helper) { rspec.spec_dir } 86 | watch(rails.routes) { "#{rspec.spec_dir}/routing" } 87 | watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } 88 | 89 | # Capybara features specs 90 | watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") } 91 | watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") } 92 | 93 | # Turnip features and steps 94 | watch(%r{^spec/acceptance/(.+)\.feature$}) 95 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| 96 | Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Simon Loffler (https://sighmon.com) 2 | 3 | Based on Markerb Gem: 4 | 5 | Copyright 2011-2015 Plataformatec (http://blog.plataformatec.com.br) 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MJML-Rails 2 | 3 | [![Build Status](https://github.com/sighmon/mjml-rails/workflows/test/badge.svg?branch=master)](https://github.com/sighmon/mjml-rails/actions?query=workflow%3Atest+branch%3Amaster) [![Gem Version](https://badge.fury.io/rb/mjml-rails.svg)](https://badge.fury.io/rb/mjml-rails) 4 | 5 | **MJML-Rails** allows you to render HTML emails from an [MJML](https://mjml.io) template. 6 | 7 | **Note**: As of MJML 4.3.0 you can no longer use `` directly inside an ``, wrap it in ``. 8 | 9 | An example template might look like: 10 | 11 | ```erb 12 | 13 | 14 | 15 | Hello World 16 | 17 | 18 | 19 | 20 | Hello World 21 | <%= render partial: "info", formats: [:html] %> 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | And the partial: 29 | 30 | ```erb 31 | 32 | This is <%= @user.username %> 33 | ``` 34 | 35 | * Notice you can use ERB and partials inside the template. 36 | 37 | Your `user_mailer.rb` might look like this: 38 | 39 | ```ruby 40 | # ./app/mailers/user_mailer.rb 41 | class UserMailer < ActionMailer::Base 42 | def user_signup_confirmation 43 | mail(to: "user@example.com", from: "app@example.com") do |format| 44 | format.text 45 | format.mjml 46 | end 47 | end 48 | end 49 | ``` 50 | 51 | ## Example application 52 | 53 | * [MJML with Rails 6](https://github.com/dyanagi/example_mjml_rails): Renders HTML emails with MJML layout, view, and partial. 54 | 55 | ## Installation 56 | 57 | ### Using MJML NPM package 58 | 59 | Add it to your Gemfile. 60 | 61 | ```ruby 62 | gem 'mjml-rails' 63 | ``` 64 | 65 | Run the following command to install it: 66 | 67 | ```console 68 | bundle install 69 | ``` 70 | 71 | After installation, you can generate the MJML initializer file: 72 | 73 | ```console 74 | rails generate mjml:install 75 | ``` 76 | 77 | This will create `config/initializers/mjml.rb` with default configuration options. 78 | 79 | Add the MJML parser to your project with your favourite package manager: 80 | 81 | ```console 82 | # with npm 83 | npm install mjml 84 | 85 | # or install it globally (The best way for Rails 7.x.x with importmaps) 86 | npm install -g mjml 87 | 88 | # with yarn 89 | yarn add mjml 90 | 91 | # with bun 92 | bun add mjml 93 | ``` 94 | 95 | MJML-Rails falls back to a global installation of MJML but it is strongly recommended to add MJML directly to your project. 96 | 97 | You'll need at least Node.js version 6 for MJML to function properly. 98 | 99 | ### Using MRML with included binaries 100 | 101 | If for some reason you can't or don't want to run JS code in your production environment, you can use [MRML](https://github.com/hardpixel/mrml-ruby). It ships with already compiled binaries for Rust implementation of MJML so it has no external dependencies. 102 | 103 | Add `mjml-rails` and `mrml` to your Gemfile. 104 | 105 | ```ruby 106 | gem 'mjml-rails' 107 | gem 'mrml' 108 | ``` 109 | 110 | Run the following command to install it: 111 | 112 | ```console 113 | bundle install 114 | ``` 115 | 116 | Set `use_mrml` option to `true` in your initializer: 117 | 118 | ```ruby 119 | # config/initializers/mjml.rb 120 | Mjml.setup do |config| 121 | config.use_mrml = true 122 | end 123 | ``` 124 | 125 | **Note**: MRML does not fully support all MJML functionalities, see [Missing implementations](https://github.com/jdrouet/mrml#missing-implementations) 126 | 127 | ## Configuration 128 | 129 | MJML-Rails has the following settings with defaults: 130 | 131 | - `template_language: :erb` 132 | 133 | ERB can be used inside MJML templates by default. Possible values are all template languages that you have installed, e.g. `:haml` or `:slim`. 134 | 135 | **Note:** If you're using Haml/Slim layouts, please don't put `` in comments in your partial. Read more at [#34](https://github.com/sighmon/mjml-rails/issues/34). 136 | 137 | - `raise_render_exception: true` 138 | 139 | Exceptions will be raised and passed to your application by default. 140 | 141 | Beware that setting it to `false` leads to an empty html email when an exception is raised, so only set this to `false` if you do not rely on html (e.g. you have a text fallback for your emails). 142 | 143 | - `minify: false` 144 | 145 | - `beautify: true` 146 | 147 | - `validation_level: "strict"` 148 | 149 | MJML-Rails will raise an exception on any template error by default. 150 | 151 | If set to `soft`, MJML will render invalid templates and ignore invalid parts. This means in case of an invalid template those invalid parts will be missing from the output. 152 | 153 | See [MJML validation documentation](https://github.com/mjmlio/mjml/tree/master/packages/mjml-validator#validating-mjml) for all possible values. 154 | 155 | - `mjml_binary: nil` 156 | 157 | This can be used to specify the path to a custom MJML binary if it is not detected automatically (shouldn't be needed). 158 | 159 | - `mjml_binary_version_supported: "4."` 160 | 161 | MJML-Rails checks the version of the MJML binary and fails if it does not start with this version, e.g. if an old version is installed by accident. 162 | 163 | - `use_mrml: false` 164 | Enabling this will allow you to use Rust implementation of MJML via the `mrml` gem. It comes with prebuilt binaries instead of having to install MJML along with Node. When enabled the options `mjml_binary_version_supported`, `mjml_binary`, `minify`, `beautify` and `validation_level` are ignored. 165 | 166 | - `cache_mjml: false` 167 | By default, MJML-Rails does not cache compiled templates. Setting this to `true` will cache compiled templates in `tmp/mjml_cache` to improve performance for frequently used templates. 168 | 169 | - `fonts` 170 | By default, MJML-Rails uses MJML default fonts, but enables you to override it. 171 | Example : `config.fonts = { Raleway: 'https://fonts.googleapis.com/css?family=Raleway }` 172 | 173 | 174 | ```ruby 175 | # config/initializers/mjml.rb 176 | Mjml.setup do |config| 177 | # Use :haml as a template language 178 | config.template_language = :haml 179 | 180 | # Ignore errors silently 181 | config.raise_render_exception = false 182 | 183 | # Optimize the size of your emails 184 | config.beautify = false 185 | config.minify = true 186 | 187 | # Render MJML templates with errors 188 | config.validation_level = "soft" 189 | 190 | # Use MRML instead of MJML, false by default 191 | config.use_mrml = false 192 | 193 | # Use custom MJML binary with custom version 194 | config.mjml_binary = "/path/to/custom/mjml" 195 | config.mjml_binary_version_supported = "3.3.5" 196 | 197 | # Use default system fonts instead of google fonts 198 | config.fonts = {} 199 | 200 | # Uncomment this to enable template caching 201 | # config.cache_mjml = true 202 | end 203 | ``` 204 | 205 | ### MJML v3.x & v4.x support 206 | 207 | Version 4.x of this gem brings support for MJML 4.x 208 | 209 | Version 2.3.x and 2.4.x of this gem brings support for MJML 3.x 210 | 211 | If you'd rather still stick with MJML 2.x then lock the mjml-rails gem: 212 | 213 | ```ruby 214 | gem 'mjml-rails', '2.2.0' 215 | ``` 216 | 217 | For MJML 3.x lock the mjml-rails gem: 218 | 219 | ```ruby 220 | gem 'mjml-rails', '2.4.3' 221 | ``` 222 | 223 | And then to install MJML 3.x 224 | 225 | ```console 226 | npm install -g mjml@3.3.5 227 | ``` 228 | 229 | ### How to guides 230 | 231 | [Kitty Giraudel](https://twitter.com/KittyGiraudel) wrote a post on [using MJML in Rails](http://dev.edenspiekermann.com/2016/06/02/using-mjml-in-rails/). 232 | 233 | ## Using Email Layouts 234 | 235 | *Note*: [Aleksandrs Ļedovskis](https://github.com/aleksandrs-ledovskis) kindly updated the gem for better Rails Email Layouts support - it should be a non-breaking change, but check the updated file naming below if you experience problems. 236 | 237 | Mailer: 238 | ```ruby 239 | # mailers/my_mailer.rb 240 | class MyMailer < ActionMailer::Base 241 | layout "default" 242 | 243 | def foo_bar(user) 244 | @recipient = user 245 | 246 | mail(to: user.email, from: "app@example.com") do |format| 247 | format.html # This will look for "default.html.erb" and then "default.html.mjml" 248 | end 249 | end 250 | end 251 | ``` 252 | 253 | Note: If `default.html.erb` exists, email will be rendered as ERB, and MJML tags will not be compiled. 254 | 255 | Email layout: 256 | ```html 257 | 258 | 259 | 260 | <%= yield %> 261 | 262 | 263 | ``` 264 | 265 | Email view: 266 | ```html 267 | 268 | <%= render partial: "to" %> 269 | 270 | 271 | 272 | 273 | Something foo regarding bar! 274 | 275 | 276 | 277 | ``` 278 | 279 | Email partial: 280 | ```html 281 | 282 | 283 | 284 | 285 | Hello <%= @recipient.name %>, 286 | 287 | 288 | 289 | ``` 290 | 291 | ## Sending Devise user emails 292 | 293 | If you use [Devise](https://github.com/plataformatec/devise) for user authentication and want to send user emails with MJML templates, here's how to override the [devise mailer](https://github.com/plataformatec/devise/blob/master/app/mailers/devise/mailer.rb): 294 | ```ruby 295 | # app/mailers/devise_mailer.rb 296 | class DeviseMailer < Devise::Mailer 297 | def reset_password_instructions(record, token, opts={}) 298 | @token = token 299 | @resource = record 300 | # Custom logic to send the email with MJML 301 | mail( 302 | template_path: 'devise/mailer', 303 | from: "some@email.com", 304 | to: record.email, 305 | subject: "Custom subject" 306 | ) do |format| 307 | format.text 308 | format.mjml 309 | end 310 | end 311 | end 312 | ``` 313 | 314 | Now tell devise to user your mailer in `config/initializers/devise.rb` by setting `config.mailer = 'DeviseMailer'` or whatever name you called yours. 315 | 316 | And then your MJML template goes here: `app/views/devise/mailer/reset_password_instructions.mjml` 317 | 318 | Devise also have [more instructions](https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer) if you need them. 319 | 320 | ## Deploying with Heroku 321 | 322 | To deploy with [Heroku](https://heroku.com) you'll need to setup [multiple buildpacks](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app) so that Heroku first builds Node for MJML and then the Ruby environment for your app. 323 | 324 | Once you've installed the [Heroku Toolbelt](https://toolbelt.heroku.com/) you can setup the buildpacks from the commandline: 325 | 326 | `$ heroku buildpacks:set heroku/ruby` 327 | 328 | And then add the Node buildpack to index 1 so it's run first: 329 | 330 | `$ heroku buildpacks:add --index 1 heroku/nodejs` 331 | 332 | Check that's all setup by running: 333 | 334 | `$ heroku buildpacks` 335 | 336 | Next you'll need to setup a `package.json` file in the root, something like this: 337 | 338 | ```json 339 | { 340 | "name": "your-site", 341 | "version": "1.0.0", 342 | "description": "Now with MJML email templates!", 343 | "main": "index.js", 344 | "directories": { 345 | "doc": "doc", 346 | "test": "test" 347 | }, 348 | "dependencies": { 349 | "mjml": "^4.0.0" 350 | }, 351 | "repository": { 352 | "type": "git", 353 | "url": "git+https://github.com/your-repo/your-site.git" 354 | }, 355 | "keywords": [ 356 | "mailer" 357 | ], 358 | "author": "Your Name", 359 | "license": "ISC", 360 | "bugs": { 361 | "url": "https://github.com/sighmon/mjml-rails/issues" 362 | }, 363 | "homepage": "https://github.com/sighmon/mjml-rails" 364 | } 365 | ``` 366 | 367 | Then `$ git push heroku master` and it should Just WorkTM. 368 | 369 | ## Bug reports 370 | 371 | If you discover any bugs, feel free to create an issue on GitHub. Please add as much information as possible to help us fixing the possible bug. We also encourage you to help even more by forking and sending us a pull request. 372 | 373 | [github.com/sighmon/mjml-rails/issues](https://github.com/sighmon/mjml-rails/issues) 374 | 375 | ## Maintainers 376 | 377 | * Simon Loffler [github.com/sighmon](https://github.com/sighmon) 378 | * Steven Pickles [github.com/thatpixguy](https://github.com/thatpixguy) 379 | * [The Rails community](https://github.com/sighmon/mjml-rails/pulls?q=is%3Apr+is%3Aclosed). :-) 380 | 381 | ## Other similar gems 382 | 383 | * [srghma/mjml-premailer](https://github.com/srghma/mjml-premailer) 384 | * [kolybasov/mjml-ruby/](https://github.com/kolybasov/mjml-ruby/) 385 | 386 | ## License 387 | 388 | MIT License. Copyright 2018 Simon Loffler. [sighmon.com](http://sighmon.com) 389 | 390 | Lovingly built on [github.com/plataformatec/markerb](https://github.com/plataformatec/markerb) 391 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | Bundler::GemHelper.install_tasks 5 | 6 | require 'rake/testtask' 7 | require 'rdoc/task' 8 | 9 | desc 'Default: run unit tests.' 10 | task default: :test 11 | 12 | desc 'Test the simple_form plugin.' 13 | Rake::TestTask.new(:test) do |t| 14 | t.libs << 'lib' 15 | t.libs << 'test' 16 | t.pattern = 'test/**/*_test.rb' 17 | t.verbose = true 18 | end 19 | 20 | desc 'Generate documentation for the mjml plugin.' 21 | RDoc::Task.new(:rdoc) do |rdoc| 22 | rdoc.rdoc_dir = 'rdoc' 23 | rdoc.title = 'Mjml' 24 | rdoc.options << '--line-numbers' 25 | rdoc.rdoc_files.include('README.md') 26 | rdoc.rdoc_files.include('lib/**/*.rb') 27 | end 28 | -------------------------------------------------------------------------------- /archive/mjml-rails-2.1.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.1.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.1.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 7a754fd1fca50d5186f9e37c77400aa67a1c4374c61efffa59471b1bb0354901cae146169fb67aa45ffe0f28700bece0bc384466786ba1b97bd8487436bc04df -------------------------------------------------------------------------------- /archive/mjml-rails-2.1.4.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.1.4.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.1.4.1.gem.sha512: -------------------------------------------------------------------------------- 1 | b322768da7a1ed0e791bd73126316bf6551946ee1d9fc30e865289653e509bb64da191046624d9f1ed52fd3f7dbf6b96d6b61f0259b094b4e8bf7c7d2ceb38ca -------------------------------------------------------------------------------- /archive/mjml-rails-2.1.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.1.4.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.1.4.gem.sha512: -------------------------------------------------------------------------------- 1 | 98d895ac5b9fb6140037878e5b213bd31ece4e105540451a0e6a1a626e8f4b6399dcb7e8b0354fce1361fdcba456d0ff146e3a96ee90d15471948d76aadd1d06 -------------------------------------------------------------------------------- /archive/mjml-rails-2.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.2.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.2.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 773730f75babe5b4032a77b24a5121def85e22722ae7074cd4845c31f478a08895d6301ee1b0b9cc682132d2ab99d89361bedd6e98a3851dd93786ee8fd20c81 -------------------------------------------------------------------------------- /archive/mjml-rails-2.3.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.3.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.3.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 712c2a79d36f485f203e5bb962e77f9d936c426f1df87c802fa646f4e94edb6933c8e719f0babe299ff2cf3261314f03589acff1a63cf7d28c6286f6877489d9 -------------------------------------------------------------------------------- /archive/mjml-rails-2.3.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.3.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.3.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 3951b7afcb6b68ae79ed7d49ce1acd59d858cf9761280250d3bb56e05cd31cb89c549aeaa67d387d9bac851037cca49ef8fe7de6034b47b551603f6d724b04dd -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.4.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.0.gem.sha512: -------------------------------------------------------------------------------- 1 | ae0b2f49364c178790f1bb1dfeaada60f12331341eb5725e69c81494e8a4d5a01c9bf0ba0412ba7dc40fe3657169bb72bef9e850ba522633db60d50bbb0d533a -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.4.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 0afe0242ea2ced0cf10ed1b1ecf55a23ffcac9e494cb06f6337c6bea47cae8ffa122ace0d26e9e375ba4f3b33f163c1f3dcbef8dc9bea7c9a0305535148fa2fa -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.4.2.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.2.gem.sha512: -------------------------------------------------------------------------------- 1 | 4d522fd898aad1098ffad5fca23447f66cce9b45390cdc618c234e2cce90d05cc7e5193fafce37a4863feac2de9c8076dd8d98d129296e4f4fe0872aa1f7ccbc -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-2.4.3.gem -------------------------------------------------------------------------------- /archive/mjml-rails-2.4.3.gem.sha512: -------------------------------------------------------------------------------- 1 | 51dc5fc02e84f4dffee606e45a48d51e78fc61a0adc878988342b93f6a7ecb05e5bff3443c74ead20e247af1212f30cadd44278f8ee146836eea82f672f900b1 -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.0.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.0.gem.sha512: -------------------------------------------------------------------------------- 1 | bc81bfde5219c568a6109b9e6bacfe0489090bef67696cd3dd2dbebf2ee520f236d946c57216cef83877eb263920cb3d6e1b2499f5d67fb47556e13006ba8e5e -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.0.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.1.gem.sha512: -------------------------------------------------------------------------------- 1 | f1ce932435b76f5e35d253018f01f4d4e44b0a5da3435ac5e271551072896d0a91125f05d176b585a483c5b27e44653f962860f28a885e23b03aa4d885827dba -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.0.2.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.2.gem.sha512: -------------------------------------------------------------------------------- 1 | 0b0818377a1a293e957c9993d5074192cd2f7facd60f9cd78fe58f6a43447710da9b6d38df66d6c6de6636cbfe530332f03d2c4eac990f264d775db45ef2070a -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.0.3.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.0.3.gem.sha512: -------------------------------------------------------------------------------- 1 | acfa9343980c9bf2494c690413891ab806b6441aea00f8dd4424b5bf36a2487e2c979bc3c7d632fc728c61d83439da5fb9934958464dcc4e1654ef37993c39d1 -------------------------------------------------------------------------------- /archive/mjml-rails-4.1.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.1.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.1.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 9532abec59646cb03eda7acf9bbbc5a91fd34d721d1b450254d24b10a091ada5bb8ba93dccd6dc0ccf66e5976ea65f537d0acd0a17db472911357e0540eeffbb -------------------------------------------------------------------------------- /archive/mjml-rails-4.10.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.10.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.10.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 4b42db3ec566d911984f3169b727ae3b1046e9a478ef6d6f4372a5a5ba814b4842a729a2021a16df6e3652a0cf4f94ae2aba49fca3a0ec81dc83ea62814949d5 -------------------------------------------------------------------------------- /archive/mjml-rails-4.10.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.10.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.10.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 99b94c070b25a9c0debc5531e5c095cb7a21c97b94a7ba9f4f2a29baa303115a31d5dbb1f51dda15eddf7f976e02dfcba5bfa5c55745bf68daa9915ab3128bf4 -------------------------------------------------------------------------------- /archive/mjml-rails-4.11.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.11.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.11.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 6238c7a4fd708cf7fa3dbe7127268561a02b1159fd85aa6d0d9af8815119d285d882ad118f122cc91fcce795ab3e408b635a890b623e8bcabfd76214cb142899 -------------------------------------------------------------------------------- /archive/mjml-rails-4.12.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.12.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.12.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 408166931fbb865e70fc01b572aa96129c5c4ffc21d4ca6be3e79fd33ebbeb8b3fa7c54fff14bdc0de00217e0586648cbd5ce779dc6a38a3b2919d861b2c0290 -------------------------------------------------------------------------------- /archive/mjml-rails-4.12.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.12.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.12.1.gem.sha512: -------------------------------------------------------------------------------- 1 | bb4b91615954a7a035feea8ee32f3b09e4469a7d53b92b6d9df2c84c2057c21478bde35d5fa62784adc6de179b40c4bbc6cd7cbfb48a7c5e3a3bd8bda71b865a -------------------------------------------------------------------------------- /archive/mjml-rails-4.13.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.13.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.13.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 775e26a90ce9d98b7806e311a2351e87594e80853308ef1874578a4bf63b477f4314b90e188bd8137cc823cecef941a4f55d3e58571620019eb7b9fd50a2800f -------------------------------------------------------------------------------- /archive/mjml-rails-4.14.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.14.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.14.0.gem.sha512: -------------------------------------------------------------------------------- 1 | ab4bb873748b9ebb45b4c7fade0ded354f813729aa68caf471fc6737ab0f4d748eb1770fb675e5397d7d879c13c27493573a63baf190a6219931ce800bcd56ee -------------------------------------------------------------------------------- /archive/mjml-rails-4.14.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.14.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.14.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 45a292c5eb12f6b9bd733e4f91e69a5d2544352d3f0ac1164598b8c6aa73537ef0d9456b0c43eb385a8bb4f86ece28c6c7d7b5cc0d255efdac1c67cb024cfcb4 -------------------------------------------------------------------------------- /archive/mjml-rails-4.15.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.15.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.15.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 6d91cb108595fb241f659cf46a5e8e778935452422a27995a71e57e0484597e480502c6963d533a230e199ea4212c8e63988edc8e09a568e0411feccc8ba0167 -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.2.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 5d355941ef331267c81d4f386fef53c428a2584c561fd3c1d515fbd065761aa04e46999c339a7d7a9d5640c8157d92e5f6c8a957479d80d1864a3c73d79aa2aa -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.2.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 334a098832d4f30b411c825a9c0009b9bb9039cfdcaf92bfbe72395dafa485ecbee11c5456cf6b9ce0e9caa0e461618636fddf31d5784d297e99b5f3e583823a -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.2.2.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.2.gem.sha512: -------------------------------------------------------------------------------- 1 | e53c2cccb4700eb38f32f842c9bb33de9e368b57356afc73aea86f2074508cc3725dcb17c2c082f09b0bdd235e8370cc8ca5b3bf4c12e94322bd65c4a97311c0 -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.3.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.2.3.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.3.gem.sha512: -------------------------------------------------------------------------------- 1 | 060203ad09178106dcbc1f4d66c2402ab440e8bd1bf781f50e9c152f592b0b6a93bdd993f4b75e8d3bc9034fbe865fe9d9a082d2273affe7cbe06b2c728ce3ec -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.4.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.2.4.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.4.gem.sha512: -------------------------------------------------------------------------------- 1 | f8d022b53cd4a9d9282ab45b68a6f9a3e40e7895be0780d39e6ed1e2ec9f7c4e10e6a5140b70e6b39356545d0b5394b044e30c1e5d0267a17d7c30d8f0baa366 -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.5.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.2.5.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.2.5.gem.sha512: -------------------------------------------------------------------------------- 1 | b8510ed6c1e7e2b5417fab34146a8a34f034f3c244876e7f5f7902d520c895374d4ba50d58630a923b8520330edf5185ef033714342c3df997b430cc017a3509 -------------------------------------------------------------------------------- /archive/mjml-rails-4.3.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.3.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.3.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 2f01fdabbd8e0fe26b1a91654cce5182aa4b08ff9e83519ac215b0908a40eeee7e7e938dc55fdef779fbe0f43b9815a3a8c4c00d420917214660550483af6615 -------------------------------------------------------------------------------- /archive/mjml-rails-4.3.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.3.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.3.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 6fdba94741b1ce45465b6a2e7bc381dbb7f46c7bf0f66c64837b2c068a9db066c67c5f54db610716fb2ec6c78c1e6c9b1cdba3e76b9d5d38d1584d1218343395 -------------------------------------------------------------------------------- /archive/mjml-rails-4.3.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.3.2.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.3.2.gem.sha512: -------------------------------------------------------------------------------- 1 | 5f91f78ad1ed460ba43d768b4559467853c4ac00aa3ce8e4c52d63a0c478d2e0d9697d846b0834d855c741a172f4c00bb2df69672dc0aefeb3e41ec342efc867 -------------------------------------------------------------------------------- /archive/mjml-rails-4.4.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.4.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.4.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 73459598e7dfa066f2979263332b250c44148db0f480cab8181b9fa26b4fa6c16f038e172cbee0bbcc87cacfe76e494c80d3987dc6d2c0d1dc9978d44d686d06 -------------------------------------------------------------------------------- /archive/mjml-rails-4.4.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.4.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.4.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 7c540c2d1169f2df8680fa909b0b989671cc05c8bf58b72f67fe40a3b0d0a9bf5a6a85417440cbd37a022cc9ac5d0900785637f8b3910d3c6c2c27bbc877c308 -------------------------------------------------------------------------------- /archive/mjml-rails-4.4.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.4.2.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.4.2.gem.sha512: -------------------------------------------------------------------------------- 1 | cdf58927da3c7b4f3a60054d18267c04160c020e6e0b0a7ab52a6bab5b4452b06ab9c1c639820ac54717e2ac7ac445f5a1a3489c3438450c850a1b8b14a62a29 -------------------------------------------------------------------------------- /archive/mjml-rails-4.5.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.5.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.5.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 4669e2475af9db8a849f16854cb463bee8a5734955eb87d8512e04b1182bf15ad07ff4df71f044721eae5787e8a74dd9d6ee2477f4b20fc98378e882ae62ee07 -------------------------------------------------------------------------------- /archive/mjml-rails-4.6.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.6.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.6.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 9526402bd0ef48d8d99ffaff42e23ce3f7ec0e0e712a11f916262bf8110f4fc3b5ffb94ae8c71f9696e926b14a2ac23f84832a7c2b54143602e2c0013fc6293c -------------------------------------------------------------------------------- /archive/mjml-rails-4.6.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.6.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.6.1.gem.sha512: -------------------------------------------------------------------------------- 1 | fa4d33556bb7b5b160b9d18f7643e8f1eed995b82274f374c8908ece17a9294068e60f8e68df1a3ca03453580d82b0582742e3c8c38fb88b17fd67bce8942d7f -------------------------------------------------------------------------------- /archive/mjml-rails-4.7.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.7.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.7.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 334e19c58a812fc73b483d2d477085a9ac3f073333d46b7ff46c51accb46f5bdb9860d207194c92e1868e56d67de78ce0b7ed07af14988240365f666c8868e54 -------------------------------------------------------------------------------- /archive/mjml-rails-4.7.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.7.1.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.7.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 1afb895ec49a32b81aa12466fd6c81f51d6cf5a26e4f8efef539d6ae67829e2578c0e13ae5d626c453d3927ad62bb41344d385c29ca71198d585c43f997a793b -------------------------------------------------------------------------------- /archive/mjml-rails-4.7.2.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.7.2.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.7.2.gem.sha512: -------------------------------------------------------------------------------- 1 | b4a7b0d182b32e15bd55bc9404d7971e99b3c24396ece4b403143647eb366f7f54810b573121657efa933d3c5571f418b401513e5d451d5a122103656191d8ef -------------------------------------------------------------------------------- /archive/mjml-rails-4.8.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.8.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.8.0.gem.sha512: -------------------------------------------------------------------------------- 1 | b1f76349c29b2a382fb45f41e9dfa51e1420a43c874eee7b9943fa187d1f01d8d6e1a3d10cebfe5a9dbaf23e918d91fd847ae8e717e629d3e0619735e3e6b18f -------------------------------------------------------------------------------- /archive/mjml-rails-4.9.0.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/archive/mjml-rails-4.9.0.gem -------------------------------------------------------------------------------- /archive/mjml-rails-4.9.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 5aefab694c5a519b2cc9a710e493501019b56efcec647fa273eee50d36e76e0126031e52d3fba38c215fc40f6bebac14f7ee1168e9983674b567b05f681340cb -------------------------------------------------------------------------------- /certs/sighmon.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEdDCCAtygAwIBAgIBATANBgkqhkiG9w0BAQsFADBAMRAwDgYDVQQDDAdzaWdo 3 | bW9uMRcwFQYKCZImiZPyLGQBGRYHc2lnaG1vbjETMBEGCgmSJomT8ixkARkWA2Nv 4 | bTAeFw0yNDA4MjQxMDM4MTNaFw0yNTA4MjQxMDM4MTNaMEAxEDAOBgNVBAMMB3Np 5 | Z2htb24xFzAVBgoJkiaJk/IsZAEZFgdzaWdobW9uMRMwEQYKCZImiZPyLGQBGRYD 6 | Y29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAuEka244tMe80fy0y 7 | YPZ8DXPWGV39QTdTmuTiz3sQ8bSP2ckTzmig/0eT8XKHzYQbkOB00auQX6mwYQpD 8 | OphRHPhDcEnPdGRmSIObSXujAFD8tq3ZcVd2bGZ8w8aHHRn5wNDwezLFbTYIhtr2 9 | xMdOsSSdcXtslyfxRrLM+am0uVnaGVYWruVGABx+sCTy4qPLzvbF5r+YToV2zl7G 10 | y/ZD/YsYnqhrvHWcBt/5tdzvP340UXr3fqoDhfUMD3WrziQLspgYyV65lBA9MMNt 11 | dNbXNJDk1nLt8UHuWN9r15GEdnFFs4XryrG0dmsvYAQ+JmVgFvVEFa5dFeTYhntB 12 | /h6/1BUgbqtQBDi1e2T0fIi5BxoDd1Asp5OeulyiglDAaAVCIlGdXKGjMKKX1b2N 13 | tHZj+9aj1US7cI/sGRsEenlMtoXTjew41x2UwXbHZssaOLsn/ubJr+HP3bLph9it 14 | gD4VwPpzem66FPNH/uFfAF17H11961fbTvlPtxcVj39EFMH7AgMBAAGjeTB3MAkG 15 | A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBTo6MDHQYDOj+zwdyTsCljW 16 | +zZwszAeBgNVHREEFzAVgRNzaWdobW9uQHNpZ2htb24uY29tMB4GA1UdEgQXMBWB 17 | E3NpZ2htb25Ac2lnaG1vbi5jb20wDQYJKoZIhvcNAQELBQADggGBAAj8eUP4oTrt 18 | Rnf7qJec8F2EA2mJLUz+PrGrM/eiP0jIVeGGrwfvn9hBtU+3IG6IPj16nb40T+/Q 19 | iSNIYxOZHYxj2CZf2CKKIz5slESybSlfuX/3i6WgZ3GP9X+z5jZE43fA1zR9kWIN 20 | xVl3McOoST+/UP+skagMdOl8S6qg8THdb9qTZLDT+XJVLNE8k7bcOiTKa6ef/hCR 21 | A9C/1rxJJHehHewkQQPLJg5edufj2t+BVY0tnMT24TXVCS7qy9BjZ/f1hC+4jrUA 22 | ezb/gRETp2GvGgoIrrZSiTiODKfIuhjifaxy1c+E/XfvN7gtO6awgTKHg+gt6y55 23 | ECdz0FTGporEyMBWc+GqSpfIXKKlNUsWyEEo9J3mjDfED/1nP+bePK+B3wwc69sl 24 | Qqk2dn/fFE9vdcl9OaOw2Zizne/1VFL/jkzXLqnLgbKD/q129mVCBgw2CKYnQfMN 25 | 4RwBjPyqnMxWnSq6Ycn7HdFEkgyf2cAxFfH5QtDsjEuca+/LAJMeAQ== 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /lib/generators/mjml/install/install_generator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails/generators' 4 | 5 | module Mjml 6 | module Generators 7 | class InstallGenerator < Rails::Generators::Base 8 | source_root File.expand_path('templates', __dir__) 9 | desc 'Creates MJML initializer for your application' 10 | 11 | def copy_initializer 12 | template 'mjml.rb', 'config/initializers/mjml.rb' 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/generators/mjml/install/templates/mjml.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # MJML configuration 4 | Mjml.setup do |config| 5 | # Use :erb as a template language 6 | config.template_language = :erb 7 | 8 | # Raise exceptions for template errors 9 | config.raise_render_exception = true 10 | 11 | # Beautify the output HTML 12 | config.beautify = true 13 | 14 | # Minify the output HTML 15 | config.minify = false 16 | 17 | # Validation level for MJML templates 18 | # Possible values: 'strict', 'soft' 19 | config.validation_level = 'strict' 20 | 21 | # Use MRML instead of MJML (requires mrml gem) 22 | config.use_mrml = false 23 | 24 | # Cache compiled templates for better performance 25 | config.cache_mjml = false 26 | 27 | # Custom fonts configuration 28 | # Example: config.fonts = { Raleway: 'https://fonts.googleapis.com/css?family=Raleway' } 29 | config.fonts = nil 30 | 31 | # Uncomment this to enable template caching 32 | # config.cache_mjml = true 33 | end 34 | -------------------------------------------------------------------------------- /lib/generators/mjml/mailer/mailer_generator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails/generators/erb/mailer/mailer_generator' 4 | 5 | module Mjml 6 | module Generators 7 | class MailerGenerator < Erb::Generators::MailerGenerator 8 | source_root File.expand_path('templates', __dir__) 9 | 10 | private 11 | 12 | def format 13 | :html 14 | end 15 | 16 | def formats 17 | [format] 18 | end 19 | 20 | def handler 21 | :mjml 22 | end 23 | 24 | def view_handler 25 | Mjml.template_language 26 | end 27 | 28 | def filename_with_extensions(name, file_format = format) 29 | # Due to MJML single-pass processing nature 30 | # layout files MUST have .mjml extension, but views/templates cannot 31 | is_layout_file = name.in?([:layout, 'mailer']) 32 | [name, file_format, is_layout_file ? handler : view_handler].compact.join('.') 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/generators/mjml/mailer/templates/layout.html.mjml: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%%= yield %> 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/generators/mjml/mailer/templates/view.html.erb: -------------------------------------------------------------------------------- 1 | <%= class_name %>#<%= @action %> 2 | 3 | <%%= @greeting %>, find me in app/views/<%= @path %> -------------------------------------------------------------------------------- /lib/mjml-rails.rb: -------------------------------------------------------------------------------- 1 | # rubocop:disable Naming/FileName 2 | # frozen_string_literal: true 3 | 4 | require 'mjml' 5 | # rubocop:enable Naming/FileName 6 | -------------------------------------------------------------------------------- /lib/mjml.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rubygems' 4 | require 'open3' 5 | 6 | require 'mjml/handler' 7 | require 'mjml/parser' 8 | require 'mjml/mrml_parser' 9 | require 'mjml/railtie' if defined?(Rails) 10 | 11 | module Mjml 12 | mattr_accessor \ 13 | :beautify, 14 | :minify, 15 | :fonts, 16 | :mjml_binary, 17 | :mjml_binary_error_string, 18 | :mjml_binary_version_supported, 19 | :raise_render_exception, 20 | :template_language, 21 | :validation_level, 22 | :use_mrml, 23 | :cache_mjml 24 | 25 | mattr_writer :valid_mjml_binary 26 | 27 | self.template_language = :erb 28 | self.raise_render_exception = true 29 | self.mjml_binary_version_supported = '4.' 30 | self.mjml_binary_error_string = "Couldn't find the MJML #{Mjml.mjml_binary_version_supported} binary.." \ 31 | ' have you run $ npm install mjml?' 32 | self.beautify = true 33 | self.minify = false 34 | self.validation_level = 'strict' 35 | self.use_mrml = false 36 | self.fonts = nil 37 | self.cache_mjml = false 38 | 39 | def self.check_version(bin) 40 | stdout, _, status = run_mjml('--version', mjml_bin: bin) 41 | status.success? && stdout.include?("mjml-core: #{Mjml.mjml_binary_version_supported}") 42 | rescue StandardError 43 | false 44 | end 45 | 46 | def self.run_mjml(args, mjml_bin: valid_mjml_binary) 47 | Open3.capture3("#{mjml_bin} #{args}") 48 | end 49 | 50 | def self.which(command) 51 | if Gem.win_platform? 52 | stdout, _, status = Open3.capture3("where #{command}") 53 | else 54 | stdout, _, status = Open3.capture3("which #{command}") 55 | end 56 | status.success? ? stdout.chomp : nil 57 | rescue Errno::ENOENT 58 | nil 59 | end 60 | 61 | def self.valid_mjml_binary 62 | self.valid_mjml_binary = @@valid_mjml_binary || 63 | check_for_custom_mjml_binary || 64 | check_for_mrml_binary || 65 | check_for_bun_mjml_binary || 66 | check_for_package_mjml_binary || 67 | check_for_global_mjml_binary 68 | 69 | return @@valid_mjml_binary if @@valid_mjml_binary 70 | 71 | puts Mjml.mjml_binary_error_string 72 | end 73 | 74 | def self.check_for_custom_mjml_binary 75 | if const_defined?('BIN') && Mjml::BIN.present? 76 | logger.warn('Setting `Mjml::BIN` is deprecated and will be removed in a future version! ' \ 77 | 'Please use `Mjml.mjml_binary=` instead.') 78 | self.mjml_binary = Mjml::BIN 79 | remove_const 'BIN' 80 | end 81 | 82 | return if mjml_binary.blank? 83 | 84 | return mjml_binary if check_version(mjml_binary) 85 | 86 | raise "MJML.mjml_binary is set to '#{mjml_binary}' but MJML-Rails could not validate that " \ 87 | 'it is a valid MJML binary. Please check your configuration.' 88 | end 89 | 90 | def self.check_for_mjml_package(package_manager, bin_command, binary_path) 91 | pm_bin = Mjml.which(package_manager) 92 | return unless pm_bin 93 | 94 | stdout, _, status = Open3.capture3("#{pm_bin} #{bin_command}") 95 | return unless status.success? 96 | 97 | mjml_bin = File.join(stdout.chomp, *binary_path) 98 | return mjml_bin if check_version(mjml_bin) 99 | rescue Errno::ENOENT # package manager is not installed 100 | nil 101 | end 102 | 103 | def self.check_for_bun_mjml_binary 104 | return unless Mjml.which('bun') 105 | 106 | # HINT: Bun always prioritizes local bins first and falls back to global installations 107 | mjml_bin = 'bun run mjml' 108 | 109 | return mjml_bin if check_version(mjml_bin) 110 | end 111 | 112 | def self.check_for_package_mjml_binary 113 | check_for_mjml_package('npm', 'root', ['.bin', 'mjml']) || 114 | check_for_mjml_package('yarn', 'bin mjml', []) 115 | end 116 | 117 | def self.check_for_global_mjml_binary 118 | mjml_bin = Mjml.which('mjml') 119 | return unless mjml_bin 120 | 121 | return mjml_bin if mjml_bin.present? && check_version(mjml_bin) 122 | end 123 | 124 | def self.check_for_mrml_binary 125 | return unless Mjml.use_mrml 126 | 127 | MRML.present? 128 | rescue NameError 129 | Mjml.mjml_binary_error_string = 'Couldn\'t find MRML - did you add \'mrml\' to your Gemfile?' 130 | false 131 | end 132 | 133 | def self.discover_mjml_bin 134 | logger.warn('`Mjml.discover_mjml_bin` is deprecated and has no effect anymore! ' \ 135 | 'Please use `Mjml.mjml_binary=` to set a custom MJML binary.') 136 | end 137 | 138 | def self.setup 139 | yield self if block_given? 140 | end 141 | 142 | class << self 143 | attr_writer :logger 144 | 145 | def logger 146 | @logger ||= Logger.new($stdout).tap do |log| 147 | log.progname = name 148 | end 149 | end 150 | end 151 | end 152 | -------------------------------------------------------------------------------- /lib/mjml/cache.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Mjml 4 | class Cache 5 | attr_reader :template_path 6 | 7 | def initialize(template_path) 8 | @template_path = template_path 9 | end 10 | 11 | # @yield [] -> String 12 | # @return [String] 13 | def cache(&block) 14 | return yield if !Mjml.cache_mjml && block 15 | 16 | cached_path = cached_file_path 17 | if File.exist?(cached_path) 18 | File.read(cached_path) 19 | else 20 | html_content = yield if block 21 | File.write(cached_path, html_content) 22 | html_content 23 | end 24 | end 25 | 26 | private 27 | 28 | def cached_file_path 29 | File.join(cache_directory, "#{fingerprint}.html") 30 | end 31 | 32 | def fingerprint 33 | full_path = File.join(Dir.pwd, 'app', 'views', "#{template_path}.mjml") 34 | raise "Template file not found: #{full_path}" unless File.exist?(full_path) 35 | 36 | Digest::SHA256.hexdigest(File.read(full_path)) 37 | end 38 | 39 | def cache_directory 40 | dir = File.join(Dir.pwd, 'tmp', 'mjml_cache') 41 | FileUtils.mkdir_p(dir) unless Dir.exist?(dir) 42 | dir 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/mjml/handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'action_view' 4 | require 'action_view/template' 5 | require 'rails/version' 6 | 7 | module Mjml 8 | class Handler 9 | def template_handler 10 | @template_handler ||= ActionView::Template.registered_template_handler(Mjml.template_language) 11 | end 12 | 13 | # Optional second source parameter to make it work with Rails >= 6: 14 | # Beginning with Rails 6 template handlers get the source of the template as the second 15 | # parameter. 16 | def call(template, source = nil) 17 | compiled_source = compile_source(source, template) 18 | 19 | parser_class = Mjml.use_mrml ? 'MrmlParser' : 'Parser' 20 | template_path = template.virtual_path 21 | # Per MJML v4 syntax documentation[0] valid/render'able document MUST start with root tag 22 | # If we get here and template source doesn't start with one it means 23 | # that we are rendering partial named according to legacy naming convention (partials ending with '.mjml') 24 | # Therefore we skip MJML processing and return raw compiled source. It will be processed 25 | # by MJML library when top-level layout/template is rendered 26 | # 27 | # [0] - https://github.com/mjmlio/mjml/blob/master/doc/components_1.md#mjml 28 | if //i.match?(compiled_source) 29 | "Mjml::#{parser_class}.new('#{template_path}', begin;#{compiled_source};end).render.html_safe" 30 | else 31 | compiled_source 32 | end 33 | end 34 | 35 | private 36 | 37 | def compile_source(source, template) 38 | if Rails::VERSION::MAJOR >= 6 39 | template_handler.call(template, source) 40 | else 41 | template_handler.call(template) 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/mjml/mrml_parser.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Mjml 4 | class MrmlParser 5 | attr_reader :template_path, :input 6 | 7 | # Create new parser 8 | # 9 | # @param template_path [String] The path to the .mjml file 10 | # @param input [String] The string to transform in html 11 | def initialize(template_path, input) 12 | @template_path = template_path 13 | @input = input 14 | @with_cache = Cache.new(template_path) 15 | end 16 | 17 | # Render mjml template 18 | # 19 | # @return [String] 20 | def render 21 | @with_cache.cache do 22 | MRML.to_html(input) 23 | rescue NameError 24 | Mjml.logger.fatal('MRML is not installed. Please add `gem "mrml"` to your Gemfile.') 25 | raise 26 | rescue StandardError 27 | raise if Mjml.raise_render_exception 28 | 29 | '' 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mjml/parser.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'digest' 4 | require_relative 'cache' 5 | 6 | module Mjml 7 | class Parser 8 | class ParseError < StandardError; end 9 | 10 | attr_reader :template_path, :input 11 | 12 | # Create new parser 13 | # 14 | # @param template_path [String] The path to the .mjml file 15 | # @param input [String] The content of the .mjml file 16 | def initialize(template_path, input) 17 | raise Mjml.mjml_binary_error_string unless Mjml.valid_mjml_binary 18 | 19 | @template_path = template_path 20 | @input = input 21 | @with_cache = Cache.new(template_path) 22 | end 23 | 24 | # rubocop:disable Metrics/MethodLength 25 | # Render MJML template 26 | # 27 | # @return [String] 28 | def render 29 | @with_cache.cache do 30 | in_tmp_file = Tempfile.open(['in', '.mjml']) do |file| 31 | file.write(input) 32 | file # return tempfile from block so #unlink works later 33 | end 34 | run(in_tmp_file.path) 35 | rescue StandardError 36 | raise if Mjml.raise_render_exception 37 | 38 | '' 39 | ensure 40 | in_tmp_file&.unlink 41 | end 42 | end 43 | # rubocop:enable Metrics/MethodLength 44 | 45 | # Exec mjml command 46 | # 47 | # @return [String] The result as string 48 | def run(in_tmp_file) 49 | Tempfile.create(['out', '.html']) do |out_tmp_file| 50 | _, stderr, status = Mjml.run_mjml(build_command(in_tmp_file, out_tmp_file)) 51 | 52 | unless status.success? 53 | # The process status ist quite helpful in case of dying processes without STDERR output. 54 | # Node exit codes are documented here: https://node.readthedocs.io/en/latest/api/process/#exit-codes 55 | raise ParseError, "#{stderr.chomp}\n(process status: #{status})" 56 | end 57 | 58 | Mjml.logger.warn(stderr.chomp) if stderr.present? 59 | out_tmp_file.read 60 | end 61 | end 62 | 63 | # Build command string from config variables 64 | # 65 | # @return [String] Command string 66 | def build_command(in_file, out_file) 67 | command = "-r #{in_file} -o #{out_file.path} " \ 68 | "--config.beautify #{Mjml.beautify} " \ 69 | "--config.minify #{Mjml.minify} " \ 70 | "--config.validationLevel #{Mjml.validation_level}" 71 | command += " --config.fonts '#{Mjml.fonts.to_json}'" unless Mjml.fonts.nil? 72 | command 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/mjml/railtie.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Mjml 4 | class Railtie < Rails::Railtie 5 | config.mjml = Mjml 6 | config.app_generators.mailer template_engine: :mjml 7 | 8 | initializer 'mjml-rails.register_template_handler' do 9 | ActionView::Template.register_template_handler :mjml, Mjml::Handler.new 10 | Mime::Type.register_alias 'text/html', :mjml 11 | end 12 | 13 | config.to_prepare do 14 | # make sure we have a valid mjml binary 15 | Mjml.valid_mjml_binary 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/mjml/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Mjml 4 | # Version number no longer matches MJML.io version 5 | VERSION = '4.15.1' 6 | end 7 | -------------------------------------------------------------------------------- /mjml-rails-4.15.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sighmon/mjml-rails/e93acb5669402ce6c6fb7c47f1546f331aaee774/mjml-rails-4.15.1.gem -------------------------------------------------------------------------------- /mjml-rails-4.15.1.gem.sha512: -------------------------------------------------------------------------------- 1 | 6f6cf58b74d0fafa6f18922bb7951a229521a56434ca36ab0fe5e6cbc40db1e7698352ddb64a0e64b42bffb40510b4f83eb61ba56d7513ab4613c9735bddf2a9 -------------------------------------------------------------------------------- /mjml-rails.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $LOAD_PATH.push File.expand_path('lib', __dir__) 4 | require 'mjml/version' 5 | 6 | Gem::Specification.new do |s| # rubocop:disable Gemspec/RequireMFA 7 | s.name = 'mjml-rails' 8 | s.version = Mjml::VERSION.dup 9 | s.platform = Gem::Platform::RUBY 10 | s.summary = 'MJML + ERb templates' 11 | s.email = 'sighmon@sighmon.com' 12 | s.homepage = 'https://github.com/sighmon/mjml-rails' 13 | s.description = 'Render MJML + ERb template views in Rails' 14 | s.authors = ['Simon Loffler', 'Steven Pickles'] 15 | s.license = 'MIT' 16 | s.required_ruby_version = '>= 2.5' 17 | 18 | s.cert_chain = ['certs/sighmon.pem'] 19 | s.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $PROGRAM_NAME.end_with?('gem') 20 | 21 | s.files = Dir['MIT-LICENSE', 'README.md', 'lib/**/*'] 22 | s.test_files = Dir['test/**/*.rb'] 23 | s.require_paths = ['lib'] 24 | s.post_install_message = "Don't forget to install MJML e.g. \n$ npm install mjml" 25 | 26 | s.add_development_dependency 'byebug' 27 | s.add_development_dependency 'mocha', '2.1.0' 28 | s.add_development_dependency 'mrml', '~> 1.4.2' 29 | s.add_development_dependency 'rails' 30 | s.add_development_dependency 'rubocop', '~> 1.23.0' 31 | s.add_development_dependency 'rubocop-performance', '~> 1.12.0' 32 | s.add_development_dependency 'rubocop-rails', '~> 2.12.4' 33 | s.add_development_dependency 'warning', '1.2.1' 34 | end 35 | -------------------------------------------------------------------------------- /test/fixtures/valid-mjml-binary/empty-path/which: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # simulate GNU which's stderr message when it cannot find something 4 | >&2 echo "I should not show up in test output" 5 | 6 | # simulate an empty path by always returning nonzero 7 | exit 1 8 | -------------------------------------------------------------------------------- /test/generator_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'test_helper' 4 | require 'generators/mjml/mailer/mailer_generator' 5 | 6 | class GeneratorTest < Rails::Generators::TestCase 7 | tests Mjml::Generators::MailerGenerator 8 | destination File.expand_path('tmp', __dir__) 9 | setup :prepare_destination 10 | 11 | test 'assert all views are properly created with given name' do 12 | run_generator %w[notifier foo bar baz] 13 | 14 | assert_file 'app/views/layouts/mailer.html.mjml' do |mailer| 15 | assert_match '', mailer 16 | assert_match '', mailer 17 | assert_match '<%= yield %>', mailer 18 | end 19 | 20 | assert_file 'app/views/notifier_mailer/foo.html.erb' do |template| 21 | assert_match '<%= @greeting %>', template 22 | assert_match 'app/views/notifier_mailer/foo.html.erb', template 23 | end 24 | 25 | assert_file 'app/views/notifier_mailer/bar.html.erb' 26 | assert_file 'app/views/notifier_mailer/baz.html.erb' 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /test/mjml_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'test_helper' 4 | 5 | class NotifierMailer < ActionMailer::Base 6 | self.view_paths = File.expand_path('views', __dir__) 7 | 8 | layout 'default' 9 | 10 | def inform_contact(recipient) 11 | @recipient = recipient 12 | 13 | mail(to: @recipient, from: 'app@example.com') do |format| 14 | format.text 15 | format.html 16 | end 17 | end 18 | 19 | def invalid_template(recipient) 20 | @recipient = recipient 21 | 22 | mail(to: @recipient, from: 'app@example.com') do |format| 23 | format.html 24 | format.text 25 | end 26 | end 27 | end 28 | 29 | class NoLayoutMailer < ActionMailer::Base 30 | self.view_paths = File.expand_path('views', __dir__) 31 | 32 | layout nil 33 | 34 | def inform_contact(recipient) 35 | @recipient = recipient 36 | 37 | mail(to: @recipient, from: 'app@example.com', &:mjml) 38 | end 39 | 40 | def with_owa(recipient) 41 | @recipient = recipient 42 | 43 | mail(to: @recipient, from: 'app@example.com', &:mjml) 44 | end 45 | end 46 | 47 | class NotifierMailerTest < ActiveSupport::TestCase 48 | test 'MJML layout based multipart email is generated correctly' do 49 | email = NotifierMailer.inform_contact('user@example.com') 50 | 51 | assert_equal 'multipart/alternative', email.mime_type 52 | 53 | # To debug tests: 54 | # Mjml.logger.info email.mime_type 55 | # Mjml.logger.info email.to_s 56 | # Mjml.logger.info email.html_part.body 57 | 58 | assert_not email.html_part.body.match(%r{}) 59 | assert email.html_part.body.include?('We inform you about something') 62 | assert email.html_part.body.match(%r{this link}) 63 | assert email.html_part.body.include?('tracking-code-123') 64 | 65 | assert email.text_part.body.include?('We inform you about something') 66 | assert email.text_part.body.match(%r{Please visit https://www.example.com}) 67 | end 68 | 69 | test 'Invalid template raises error with validation level strict' do 70 | with_settings(validation_level: 'strict') do 71 | email = NotifierMailer.invalid_template('user@example.com') 72 | assert_raise(ActionView::Template::Error) { email.html_part.body.to_s } 73 | end 74 | end 75 | 76 | test 'Invalid template gets compiled with validation level soft' do 77 | # suppress warning of MJML binary 78 | Mjml.logger.stubs(:warn) 79 | 80 | with_settings(validation_level: 'soft') do 81 | email = NotifierMailer.invalid_template('user@example.com') 82 | assert email.text_part.body.include?('This is valid') 83 | assert email.html_part.body.include?('This is valid') 84 | assert_not email.html_part.body.include?('This is invalid') 85 | end 86 | end 87 | end 88 | 89 | class NotifierMailerTest < ActiveSupport::TestCase 90 | test 'old mjml-rails configuration style MJML template is rendered correctly' do 91 | email = NoLayoutMailer.inform_contact('user@example.com') 92 | 93 | assert_equal 'text/html', email.mime_type 94 | 95 | assert_not email.body.match(%r{}) 96 | assert email.body.include?('We inform you about something') 99 | assert email.body.match(%r{this link}) 100 | assert_not email.body.include?('tracking-code-123') 101 | end 102 | 103 | test 'old mjml-rails MJML template with owa is rendered correctly' do 104 | email = NoLayoutMailer.with_owa('user@example.com') 105 | 106 | assert_equal 'text/html', email.mime_type 107 | 108 | assert_not email.body.match(%r{}) 109 | assert email.body.include?('We inform you about something') 112 | assert email.body.match(%r{this link}) 113 | assert_not email.body.include?('tracking-code-123') 114 | end 115 | end 116 | 117 | describe Mjml do 118 | describe '#valid_mjml_binary' do 119 | before do 120 | Mjml.mjml_binary = nil 121 | Mjml.valid_mjml_binary = nil 122 | Mjml.use_mrml = nil 123 | end 124 | 125 | after do 126 | Mjml.mjml_binary = nil 127 | Mjml.valid_mjml_binary = nil 128 | Mjml.use_mrml = nil 129 | end 130 | 131 | it 'can be set to a custom value with mjml_binary if version is correct' do 132 | Mjml.mjml_binary = 'some custom value' 133 | Mjml.stub :check_version, true do 134 | expect(Mjml.valid_mjml_binary).must_equal 'some custom value' 135 | end 136 | end 137 | 138 | it 'raises an error if mjml_binary is invalid' do 139 | Mjml.mjml_binary = 'some custom value' 140 | err = expect { Mjml.valid_mjml_binary }.must_raise(StandardError) 141 | assert(err.message.start_with?("MJML.mjml_binary is set to 'some custom value' " \ 142 | 'but MJML-Rails could not validate that it is a valid MJML binary')) 143 | end 144 | 145 | it 'honors old Mjml::BIN way of setting custom binary' do 146 | silence_warnings { Mjml::BIN = 'set by old way' } 147 | Mjml.logger.expects(:warn).with(regexp_matches(/Setting `Mjml::BIN` is deprecated/)) 148 | err = expect { Mjml.valid_mjml_binary }.must_raise(StandardError) 149 | assert(err.message.start_with?("MJML.mjml_binary is set to 'set by old way' " \ 150 | 'but MJML-Rails could not validate that it is a valid MJML binary')) 151 | end 152 | 153 | it 'ignores empty Mjml::BIN' do 154 | Mjml::BIN = '' 155 | Mjml.mjml_binary = 'set by mjml_binary' 156 | 157 | err = expect { Mjml.valid_mjml_binary }.must_raise(StandardError) 158 | assert(err.message.start_with?("MJML.mjml_binary is set to 'set by mjml_binary' " \ 159 | 'but MJML-Rails could not validate that it is a valid MJML binary')) 160 | end 161 | 162 | it 'can use MRML and check for a valid binary' do 163 | Mjml.use_mrml = true 164 | Mjml.stubs(:check_for_custom_mjml_binary).returns(false) 165 | Mjml.stubs(:check_for_bun_mjml_binary).returns(false) 166 | Mjml.stubs(:check_for_package_mjml_binary).returns(false) 167 | Mjml.stubs(:check_for_global_mjml_binary).returns(false) 168 | expect(Mjml.valid_mjml_binary).must_equal(true) 169 | 170 | Mjml.valid_mjml_binary = nil 171 | MRML.stubs(:present?).raises(NameError) 172 | Mjml.stubs(:puts) # silence printed error message from test output 173 | assert_nil(Mjml.valid_mjml_binary) 174 | expect(Mjml.mjml_binary_error_string).must_equal 'Couldn\'t find MRML - did you add \'mrml\' to your Gemfile?' 175 | end 176 | 177 | it 'with nothing on the path, sets valid_mjml_binary to nil' do 178 | old_path = ENV['PATH'] 179 | ENV['PATH'] = './test/fixtures/valid-mjml-binary/empty-path/' 180 | 181 | Mjml.stubs(:puts) # silence printed error message from test output 182 | assert_nil(Mjml.valid_mjml_binary) 183 | ensure 184 | ENV['PATH'] = old_path 185 | end 186 | end 187 | end 188 | -------------------------------------------------------------------------------- /test/mrml_parser_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'test_helper' 4 | 5 | describe Mjml::MrmlParser do 6 | let(:parser) { Mjml::MrmlParser.new('test_template', input) } 7 | 8 | describe '#render' do 9 | describe 'when input is valid' do 10 | let(:input) { 'Hello World' } 11 | 12 | it 'returns html' do 13 | expect(parser.render).must_include 'Hello World' 14 | end 15 | end 16 | 17 | describe 'when exception is raised' do 18 | let(:input) { 'Hello World' } 19 | 20 | it 'raises exception with render exception enabled' do 21 | with_settings(raise_render_exception: true) do 22 | expect { parser.render }.must_raise(MRML::Error) 23 | end 24 | end 25 | 26 | it 'returns empty string with exception raising disabled' do 27 | with_settings(raise_render_exception: false) do 28 | expect(parser.render).must_equal '' 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/parser_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'test_helper' 4 | 5 | describe Mjml::Parser do 6 | let(:input) { mock('input') } 7 | let(:parser) { Mjml::Parser.new('test_template', input) } 8 | 9 | describe '#render' do 10 | describe 'when exception is raised' do 11 | let(:custom_error_class) { Class.new(StandardError) } 12 | let(:error) { custom_error_class.new('custom error') } 13 | 14 | before do 15 | parser.stubs(:run).raises(error) 16 | end 17 | 18 | it 'raises exception with render exception enabled' do 19 | with_settings(raise_render_exception: true) do 20 | err = expect { parser.render }.must_raise(custom_error_class) 21 | expect(err.message).must_equal error.message 22 | end 23 | end 24 | 25 | it 'returns empty string with exception raising disabled' do 26 | with_settings(raise_render_exception: false) do 27 | expect(parser.render).must_equal '' 28 | end 29 | end 30 | 31 | it 'raises unshadowed exception in case on an `Tempfile` error' do 32 | my_tempfile_error_class = Class.new StandardError 33 | with_settings(raise_render_exception: true) do 34 | Tempfile.stubs(:open).raises(my_tempfile_error_class) 35 | expect { parser.render }.must_raise(my_tempfile_error_class) 36 | end 37 | end 38 | end 39 | 40 | describe 'can read beautify, minify, fonts and validation_level configs' do 41 | it 'uses defaults if no config is set' do 42 | expect(Mjml.beautify).must_equal(true) 43 | expect(Mjml.minify).must_equal(false) 44 | expect(Mjml.validation_level).must_equal('strict') 45 | assert_nil(Mjml.fonts) 46 | end 47 | 48 | it 'uses setup config' do 49 | Mjml.setup do |config| 50 | config.beautify = false 51 | config.minify = true 52 | config.validation_level = 'soft' 53 | config.fonts = { Mononoki: 'https://cdn.jsdelivr.net/npm/@xz/fonts@1/serve/mononoki.min.css' } 54 | end 55 | 56 | expect(Mjml.beautify).must_equal(false) 57 | expect(Mjml.minify).must_equal(true) 58 | expect(Mjml.validation_level).must_equal('soft') 59 | expect(Mjml.fonts).must_equal({ Mononoki: 'https://cdn.jsdelivr.net/npm/@xz/fonts@1/serve/mononoki.min.css' }) 60 | 61 | Mjml.setup do |config| 62 | config.beautify = true 63 | config.minify = false 64 | config.validation_level = 'strict' 65 | config.fonts = nil 66 | end 67 | end 68 | end 69 | end 70 | 71 | describe '#run' do 72 | describe 'when shell command failed' do 73 | let(:error_msg) do 74 | expect { parser.run '/tmp/non_existent_file.mjml' }.must_raise(Mjml::Parser::ParseError).message 75 | end 76 | 77 | it 'raises exception' do 78 | expect(error_msg).must_include 'Command line error' 79 | end 80 | 81 | it 'includes process status' do 82 | expect(error_msg).must_match(/\(process status: .+\)/) 83 | end 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rubygems' 4 | require 'bundler' 5 | Bundler.setup 6 | 7 | require 'minitest/autorun' 8 | require 'active_support' 9 | require 'active_support/test_case' 10 | 11 | require 'action_mailer' 12 | require 'rails/railtie' 13 | require 'rails/generators' 14 | require 'rails/generators/test_case' 15 | require 'mocha/minitest' 16 | require 'byebug' 17 | require 'mrml' 18 | 19 | # require "minitest/reporters" 20 | # Minitest::Reporters.use! 21 | 22 | $LOAD_PATH.unshift File.expand_path('../lib', __dir__) 23 | require 'mjml' 24 | Mjml::Railtie.run_initializers 25 | 26 | ActiveSupport::TestCase.test_order = :sorted if ActiveSupport::TestCase.respond_to? :test_order= 27 | 28 | # Avoid annoying warning from I18n. 29 | I18n.enforce_available_locales = false 30 | 31 | ActionMailer::Base.delivery_method = :test 32 | ActionMailer::Base.perform_deliveries = true 33 | 34 | def with_settings(settings) 35 | original_settings = settings.each_with_object({}) { |(key, _), agg| agg[key] = Mjml.public_send(key) } 36 | settings.each { |key, value| Mjml.public_send("#{key}=", value) } 37 | yield 38 | ensure 39 | original_settings.each { |key, value| Mjml.public_send("#{key}=", value) } 40 | end 41 | 42 | # Suppress all ruby warnings of the mail gem, see: 43 | # * https://github.com/mikel/mail/issues/1424 44 | # * https://github.com/mikel/mail/issues/1384 45 | # * https://github.com/mikel/mail/pull/1162 46 | require 'warning' 47 | Warning.ignore(//, %r{.*gems/mail.*/lib/mail/}) 48 | -------------------------------------------------------------------------------- /test/views/layouts/_email_tracking_code.ruby: -------------------------------------------------------------------------------- 1 | unless defined? render_code 2 | def render_code 3 | # tracking-code-123 4 | Base64.decode64('dHJhY2tpbmctY29kZS0xMjM=') 5 | end 6 | end 7 | render_code 8 | -------------------------------------------------------------------------------- /test/views/layouts/default.html.mjml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Home 7 | Contacts 8 | 9 | 10 | 11 | 12 | 13 | 14 | <%= yield %> 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/views/layouts/default.text.ruby: -------------------------------------------------------------------------------- 1 | yield 2 | -------------------------------------------------------------------------------- /test/views/no_layout_mailer/_user_header.mjml: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | Welcome, <%= @recipient %>! 5 |

6 |
7 |
8 | -------------------------------------------------------------------------------- /test/views/no_layout_mailer/inform_contact.mjml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= render partial: "user_header", formats: [:html] %> 5 | 6 | 7 | 8 | 9 | 10 |

We inform you about something

11 |

12 | Please visit this link 13 |

14 |
15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /test/views/no_layout_mailer/with_owa.mjml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= render partial: "user_header", formats: [:html] %> 5 | 6 | 7 | 8 | 9 | 10 |

We inform you about something

11 |

12 | Please visit this link 13 |

14 |
15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /test/views/notifier_mailer/_user_header.html.erb: -------------------------------------------------------------------------------- 1 | 2 |

3 | Hello, <%= @recipient %>! 4 |

5 |
6 | -------------------------------------------------------------------------------- /test/views/notifier_mailer/inform_contact.html.erb: -------------------------------------------------------------------------------- 1 | <%= render "user_header" %> 2 | 3 | 4 |

We inform you about something

5 |

6 | Please visit this link 7 |

8 |
9 | -------------------------------------------------------------------------------- /test/views/notifier_mailer/inform_contact.text: -------------------------------------------------------------------------------- 1 | We inform you about something 2 | ----------------------------- 3 | 4 | Please visit https://www.example.com 5 | -------------------------------------------------------------------------------- /test/views/notifier_mailer/invalid_template.html.erb: -------------------------------------------------------------------------------- 1 | 2 | This is valid 3 | 4 | 5 | 6 | This is invalid 7 |
8 | -------------------------------------------------------------------------------- /test/views/notifier_mailer/invalid_template.text: -------------------------------------------------------------------------------- 1 | This is valid 2 | -------------------------------------------------------------------------------- /test/views/test_template.mjml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= render partial: "user_header", formats: [:html] %> 5 | 6 | 7 | 8 | 9 | 10 |

We inform you about something

11 |

12 | Please visit this link 13 |

14 |
15 |
16 |
17 |
18 |
19 | --------------------------------------------------------------------------------