├── .github └── workflows │ └── tests.yml ├── .gitignore ├── .gitmodules ├── .simplecov ├── CHANGES.md ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ └── rails_email_preview │ │ │ └── favicon.png │ └── stylesheets │ │ └── rails_email_preview │ │ ├── application.css │ │ └── bootstrap3.css ├── controllers │ └── rails_email_preview │ │ ├── application_controller.rb │ │ └── emails_controller.rb ├── helpers │ └── rails_email_preview │ │ └── emails_helper.rb ├── models │ └── rails_email_preview │ │ └── preview.rb ├── presenters │ └── rails_email_preview │ │ └── preview_list_presenter.rb └── views │ ├── integrations │ └── cms │ │ ├── _customize_cms_for_rails_email_preview.html.erb │ │ ├── comfy_v1_integration.js │ │ └── comfy_v2_integration.js │ ├── layouts │ └── rails_email_preview │ │ ├── _flash_notices.html.erb │ │ ├── application.html.erb │ │ └── email.html.erb │ └── rails_email_preview │ └── emails │ ├── _email_iframe.html.erb │ ├── _format_nav.html.erb │ ├── _headers.html.erb │ ├── _headers_and_nav.html.erb │ ├── _i18n_nav.html.erb │ ├── _nav.html.erb │ ├── _send_form.html.erb │ ├── email_iframe.js │ ├── index.html.erb │ └── show.html.erb ├── config ├── i18n-tasks.yml ├── initializers │ └── rails_email_preview.rb ├── locales │ ├── de.yml │ ├── en.yml │ ├── es.yml │ └── ru.yml └── routes.rb ├── doc └── img │ ├── rep-edit-sofa.png │ ├── rep-nav.png │ ├── rep-show-default.png │ └── rep-show.png ├── lib ├── generators │ └── rails_email_preview │ │ ├── install_generator.rb │ │ └── update_previews_generator.rb ├── rails_email_preview.rb └── rails_email_preview │ ├── delivery_handler.rb │ ├── engine.rb │ ├── integrations │ └── comfortable_mexica_sofa.rb │ ├── main_app_route_delegator.rb │ ├── version.rb │ └── view_hooks.rb ├── rails_email_preview.gemspec ├── shared.gemfile └── spec ├── dummy ├── README.rdoc ├── Rakefile ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ │ ├── .keep │ │ │ └── cat.png │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ └── application.css │ ├── controllers │ │ ├── admin_controller.rb │ │ ├── application_controller.rb │ │ └── concerns │ │ │ └── .keep │ ├── helpers │ │ └── application_helper.rb │ ├── mailer_previews │ │ ├── auth_mailer_preview.rb │ │ └── newsletter_mailer_preview.rb │ ├── mailers │ │ ├── .keep │ │ ├── application_mailer.rb │ │ ├── auth_mailer.rb │ │ └── newsletter_mailer.rb │ ├── models │ │ ├── .keep │ │ └── concerns │ │ │ └── .keep │ └── views │ │ ├── auth_mailer │ │ ├── email_confirmation.html.erb │ │ └── password_reset.html.erb │ │ ├── layouts │ │ └── admin.html.erb │ │ ├── newsletter_mailer │ │ ├── monthly_newsletter.html.erb │ │ └── weekly_newsletter.html.erb │ │ └── rails_email_preview │ │ └── _my_hook.html.erb ├── bin │ ├── bundle │ ├── rails │ └── rake ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── backtrace_silencers.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── rails_email_preview.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ ├── de.yml │ │ ├── en.yml │ │ └── es.yml │ └── routes.rb ├── lib │ └── assets │ │ └── .keep ├── log │ └── .keep └── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ └── favicon.ico ├── features ├── email_show_spec.rb ├── email_test_send_spec.rb ├── emails_list_spec.rb └── take_screenshots_spec.rb ├── gemfiles ├── i18n-tasks.gemfile ├── rails_6_1.gemfile ├── rails_7_0.gemfile └── rails_7_1.gemfile ├── preview_list_presenter_spec.rb ├── spec_helper.rb ├── support ├── save_screenshots.rb └── with_layout.rb └── update_previews_generator_spec.rb /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ main ] 4 | pull_request: 5 | types: [ opened, synchronize ] 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | include: 12 | - ruby_version: '3.3' 13 | gemfile: rails_7_1 14 | upload_coverage: true 15 | - ruby_version: '3.2' 16 | gemfile: rails_7_1 17 | # - ruby_version: '3.1' 18 | # gemfile: rails_7_1 19 | - ruby_version: '3.3' 20 | gemfile: rails_7_0 21 | - ruby_version: '3.3' 22 | gemfile: rails_6_1 23 | env: 24 | CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} 25 | BUNDLE_GEMFILE: ${{ github.workspace }}/spec/gemfiles/${{ matrix.gemfile }}.gemfile 26 | steps: 27 | - name: "Determine whether to upload coverage" 28 | if: ${{ env.CC_TEST_REPORTER_ID && matrix.upload_coverage }} 29 | run: echo COVERAGE=1 >> $GITHUB_ENV 30 | - uses: actions/checkout@v4 31 | - name: Set up Ruby ${{ matrix.ruby_version }} and ${{ matrix.gemfile }}.gemfile 32 | uses: ruby/setup-ruby@v1 33 | with: 34 | ruby-version: ${{ matrix.ruby_version }} 35 | bundler: ${{ matrix.bundler || 'Gemfile.lock' }} 36 | bundler-cache: true 37 | cache-version: 1000 38 | - name: Run tests 39 | if: ${{ !env.COVERAGE }} 40 | run: bundle exec rspec --format d 41 | - name: Run tests and upload coverage 42 | uses: paambaati/codeclimate-action@v3.0.0 43 | if: ${{ env.COVERAGE }} 44 | with: 45 | coverageCommand: bundle exec rspec --format d 46 | i18n-tasks: 47 | runs-on: ubuntu-latest 48 | env: 49 | BUNDLE_GEMFILE: ${{ github.workspace }}/spec/gemfiles/i18n-tasks.gemfile 50 | steps: 51 | - uses: actions/checkout@v4 52 | - name: Set up Ruby and i18n-tasks.gemfile 53 | uses: ruby/setup-ruby@v1 54 | with: 55 | ruby-version: 3.3 56 | bundler-cache: true 57 | - name: Run i18n-tasks 58 | run: bundle exec i18n-tasks health 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lock 2 | *.gem 3 | .idea/ 4 | .rvmrc 5 | .bundle/ 6 | .ruby-version 7 | .ruby-gemset 8 | log/*.log 9 | pkg/ 10 | spec/dummy/db/*.sqlite3 11 | spec/dummy/log/*.log 12 | spec/dummy/tmp/ 13 | coverage/ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "spec/screenshots"] 2 | path = spec/screenshots 3 | url = https://github.com/glebm/rep_spec_screenshots.git 4 | -------------------------------------------------------------------------------- /.simplecov: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | SimpleCov.start do 3 | add_filter '/spec/' 4 | add_group 'Commands', 'app/commands' 5 | add_group 'Controllers', 'app/controllers' 6 | add_group 'Forms', 'app/forms' 7 | add_group 'Helpers', 'app/helpers' 8 | add_group 'Jobs', 'app/jobs' 9 | add_group 'Mailers', %w(app/mailers app/mailer_previews) 10 | add_group 'Models', 'app/models' 11 | add_group 'Policies', 'app/policies' 12 | add_group 'View models', 'app/view_models' 13 | add_group 'Lib', 'lib/' 14 | formatter SimpleCov::Formatter::HTMLFormatter unless ENV['CI'] 15 | end 16 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | * Remove explicit dependency on `sassc-rails`. Allow the use of this gem with either: 2 | `dartsass-sprockets`, `sassc-rails`, `dartsass-rails`, or `cssbundling-rails` 3 | * Drop support for EOL ruby and rails versions (rails >6.1, ruby >3.1) 4 | 5 | ## v2.2.3 6 | 7 | * Fixes Rails 7 compatibility. 8 | [#88](https://github.com/glebm/rails_email_preview/pull/88) 9 | [#90](https://github.com/glebm/rails_email_preview/issues/90) 10 | 11 | ## v2.2.2 12 | 13 | 1. Fixes deprecation warnings on Rails 6. 14 | 2. Fixes unintentional processing of email HTML as ERB. 15 | RCE vulnerability if preview body contains user input. 16 | [#82](https://github.com/glebm/rails_email_preview/issues/82) 17 | 18 | ## v2.2.1 19 | 20 | Fixes support for Rails <5.2 (regression introduced in v2.2.0). 21 | 22 | ## v2.2.0 23 | 24 | Adds CSP nonce to inline script tags if CSP is enabled on Rails v5.2+. 25 | 26 | ## v2.1.0 27 | 28 | Use `sassc-rails` instead of `sass-rails`. 29 | 30 | ## v2.0.6 31 | 32 | CMS integration now supports Comfy v2. 33 | 34 | ## v2.0.4 35 | 36 | Depend on `sass` instead of `sass-rails`. 37 | 38 | ## v2.0.3 39 | 40 | Fix a URL generation issue in the CMS integration on Rails 5. 41 | 42 | ## v2.0.2 43 | 44 | * Document roadie-rails support. 45 | * Fix body iframe height calculation. 46 | 47 | ## v2.0.1 48 | 49 | Drop support for all versions of Rails below 4.2. 50 | Fix Rails 5 deprecation warnings. 51 | 52 | ## v1.0.3 53 | 54 | Rails 5 support. 55 | 56 | ## v1.0.2 57 | 58 | Added a couple of variables for further default theme customization. 59 | 60 | ## v1.0.1 61 | 62 | Added `RailsEmailPreview.find_preview_classes(dir)` that also finds classes in subdirectories, and changed the default 63 | initializer to load classes like this: 64 | 65 | ```ruby 66 | RailsEmailPreview.preview_classes = RailsEmailPreview.find_preview_classes('app/mailer_previews') 67 | ``` 68 | 69 | ## v1.0.0 70 | 71 | **Breaking**: REP now uses a lightweight default theme with no dependencies by default. 72 | 73 | If you are using REP with the Bootstrap 3 theme, here are the configuration changes you need to make: 74 | 75 | * `@import "rails_email_preview/bootstrap3"` instead of `rails_email_preview/application`. 76 | * Add the following styles configuration to your REP initializer: 77 | 78 | ```ruby 79 | config.style.merge!( 80 | btn_active_class_modifier: 'active', 81 | btn_danger_class: 'btn btn-danger', 82 | btn_default_class: 'btn btn-default', 83 | btn_group_class: 'btn-group btn-group-sm', 84 | btn_primary_class: 'btn btn-primary', 85 | form_control_class: 'form-control', 86 | list_group_class: 'list-group', 87 | list_group_item_class: 'list-group-item', 88 | row_class: 'row', 89 | ) 90 | ``` 91 | 92 | The following REP internal class names have changed: 93 | 94 | * `.rep-email-options` is now `.rep--email-options`. 95 | * `.rep-headers-list` is now `.rep--headers-list`. 96 | * `.rep-email-show` is now `.rep--email-show`. 97 | * `.breadcrumb` is now `.rep--breadcrumbs`. 98 | * `.breadcrumb .active` is now `.rep--breadcrumbs__active`. 99 | * `.rep-send-to-wrapper` is gone, but now there is `.rep--send-to-form`. 100 | 101 | All REP views are now wrapped in a `div` with the `rep--main-container` class. 102 | 103 | REP no longer depends on slim and slim-rails. 104 | 105 | Fixed minor email locale handling bugs in navigation and the CMS integration. 106 | 107 | ## v0.2.31 108 | 109 | * Compatibility with namespaced email classes in the CMS. 110 | 111 | ## v0.2.30 112 | 113 | * Compatibility with namespaced email classes. 114 | * Change Sass stylesheets extensions from `.sass` to `.css.sass`. [#61](https://github.com/glebm/rails_email_preview/issues/61). 115 | * Spanish translation. Thanks, @epergo! 116 | 117 | ## v0.2.29 118 | 119 | * Latest CMS compatibility 120 | * Rails 4.2: avoid deprecation warnings 121 | 122 | ## v0.2.28 123 | 124 | * CMS beta compatibility 125 | 126 | ## v0.2.27 127 | 128 | * Improve CMS compatibility 129 | * New hook: breadcrumb 130 | 131 | ## v0.2.26 132 | 133 | * Fix an issue with preview list [#47](https://github.com/glebm/rails_email_preview/issues/47). 134 | * Fix a number of minor issues. 135 | 136 | ## v0.2.25 137 | 138 | * Show attachment headers in the link's hover text (HTML title). 139 | * Faster loading via `DOMContentLoaded` on the iframe as opposed to `load`. 140 | 141 | ## v0.2.24 142 | 143 | * Fix regression: Rails 3 support. 144 | 145 | ## v0.2.23 146 | 147 | * **View hooks** to inject or replace UI selectively. 148 | * Fix regression in attachments caused by having a controller action named `headers` (name conflict). 149 | 150 | ## v0.2.22 151 | 152 | * **Preview params** set from URL query. Thank you, @OlgaGr! 153 | * Routes now include locale and part type as segments (with defaults). 154 | * Faster loading using **srcdoc** iframe attribute; new progress bar. 155 | * New language: Russian. 156 | * Minor bugfixes. 157 | 158 | ## v0.2.21 159 | 160 | * **Attachments**. Thanks, @rzane! 161 | * CMS: 1.12 compatibility, better error messages. 162 | 163 | ## v0.2.20 164 | 165 | * REP will fall back to :en if its set locale is not in the list of available locales 166 | 167 | ## v0.2.19 168 | 169 | * Fixes for CMS integration 170 | 171 | ## v0.2.18 172 | 173 | * UI language is now set to :en by default, to avoid #32 174 | * Rails 3 compatibility issues fixed 175 | 176 | ## v0.2.17 177 | 178 | * Fix preview generator 179 | 180 | ## v0.2.15 .. v0.2.16 181 | 182 | * minor bugfixes 183 | * UI improvements 184 | 185 | ## v0.2.13 .. v0.2.14 186 | 187 | * clean up dependencies 188 | * squell compatibility 189 | 190 | ## v0.2.11 .. v0.2.12 191 | 192 | * german translation thanks to @baschtl 193 | * email iframe resizes on window resize 194 | * bugfixes 195 | 196 | ## v0.2.10 197 | 198 | * simplified setting custom layout with `layout=` 199 | * bugfixes 200 | 201 | ## v0.2.9 202 | 203 | * updated bootstrap, turbolinks 204 | * internal: tests + screenshots in spec/screenshots/ after each test run 205 | 206 | ## v0.2.8 207 | 208 | bugs fixed, looks improved 209 | 210 | ## v0.2.7 211 | 212 | * config.style to customize classes in REP views 213 | 214 | ## v0.2.4 .. 0.2.6 215 | 216 | * UI enhancements 217 | * CMS integration bug fixes 218 | * Send email bug fixes 219 | 220 | ## v0.2.3 221 | 222 | * Send Email from REP 223 | 224 | ## v0.2.0 225 | 226 | * inline_main_app_routes! (enables easy layout switching) 227 | * parent_controller (enables easy authorization integration) 228 | * Backwards incompatible: root_url is now rep_root_url, internal routes are prefixed too. 229 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem 'rails' 6 | gem 'i18n-tasks' 7 | 8 | eval_gemfile './shared.gemfile' 9 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-2013 Gleb Mazovetskiy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rails Email Preview [![Build Status][badge-ci]][ci] [![Test Coverage][coverage-badge]][coverage] [![Code Climate][codeclimate-badge]][codeclimate] [](https://gitter.im/glebm/rails_email_preview?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | Preview email in the browser with this Rails engine. Compatible with Rails 6.1+. 4 | 5 | An email review: 6 | 7 | ![screenshot][rep-show-screenshot] 8 | 9 | The list of all email previews: 10 | 11 | ![screenshot][rep-nav-screenshot] 12 | 13 | REP comes with two themes: a simple standalone theme, and a theme that uses [Bootstrap 3][rep-show-default-screenshot]. 14 | 15 | ## Installation 16 | 17 | Add [![Gem Version][gem-badge]][gem] to Gemfile: 18 | 19 | ```ruby 20 | gem 'rails_email_preview', '~> 2.2.3' 21 | ``` 22 | 23 | Add an initializer and the routes: 24 | 25 | ```console 26 | $ rails g rails_email_preview:install 27 | ``` 28 | 29 | Generate preview classes and method stubs in app/mailer_previews/ 30 | 31 | ```console 32 | $ rails g rails_email_preview:update_previews 33 | ``` 34 | 35 | ## Usage 36 | 37 | The last generator above will add a stub for each of your emails, then you populate the stubs with mock data: 38 | 39 | ```ruby 40 | # app/mailer_previews/user_mailer_preview.rb: 41 | class UserMailerPreview 42 | # preview methods should return Mail objects, e.g.: 43 | def invitation 44 | UserMailer.invitation mock_user('Alice'), mock_user('Bob') 45 | end 46 | 47 | def welcome 48 | UserMailer.welcome mock_user 49 | end 50 | 51 | private 52 | # You can put all your mock helpers in a module 53 | # or you can use your factories / fabricators, just make sure you are not creating anything 54 | def mock_user(name = 'Bill Gates') 55 | fake_id User.new(name: name, email: "user#{rand 100}@test.com") 56 | end 57 | 58 | def fake_id(obj) 59 | # overrides the method on just this object 60 | obj.define_singleton_method(:id) { 123 + rand(100) } 61 | obj 62 | end 63 | end 64 | ``` 65 | 66 | ### Parameters as instance variables 67 | 68 | All parameters in the search query will be available to the preview class as instance variables. 69 | For example, if URL to mailer preview looks like: 70 | 71 | /emails/user_mailer_preview-welcome?**user_id=1** 72 | 73 | The method `welcome` in `UserMailerPreview` have a `@user_id` instance variable defined: 74 | 75 | ```ruby 76 | class UserMailerPreview 77 | def welcome 78 | user = @user_id ? User.find(@user_id) : mock_user 79 | UserMailer.welcome(user) 80 | end 81 | end 82 | ``` 83 | 84 | Now you can preview or send the welcome email to a specific user. 85 | 86 | ### Routing 87 | 88 | You can access REP urls like this: 89 | 90 | ```ruby 91 | # engine root: 92 | rails_email_preview.rep_root_url 93 | # list of emails (same as root): 94 | rails_email_preview.rep_emails_url 95 | # email show: 96 | rails_email_preview.rep_email_url('user_mailer-welcome') 97 | ``` 98 | 99 | ### Sending Emails 100 | 101 | You can send emails via REP. This is especially useful when testing with limited clients (Blackberry, Outlook, etc.). 102 | This will use the environment's mailer settings, but the handler will `perform_deliveries`. 103 | Uncomment this line in the initializer to disable sending test emails: 104 | 105 | ```ruby 106 | config.enable_send_email = false 107 | ``` 108 | 109 | ### Editing Emails 110 | 111 | Emails can be stored in the database and edited in the browser. 112 | REP works with [Comfortable Mexican Sofa CMS](https://github.com/comfy/comfortable-mexican-sofa) to achieve this -- see the [CMS Guide](https://github.com/glebm/rails_email_preview/wiki/Edit-Emails-with-Comfortable-Mexican-Sofa) to learn more. 113 | 114 | [](https://github.com/glebm/rails_email_preview/wiki/Edit-Emails-with-Comfortable-Mexican-Sofa) 115 | 116 | ### CSS inlining 117 | 118 | For CSS inlining, REP supports [Roadie](https://github.com/Mange/roadie) and 119 | [Premailer](https://github.com/alexdunae/premailer). 120 | Both of these automatically translate CSS rules into inline styles and turn 121 | relative URLs into absolute ones. 122 | 123 | Roadie additionally extracts styles that cannot be inlined into a separate 124 | ` 48 | 49 | 50 |
51 | 52 |You may have mistyped the address or the page may have moved.
55 |If you are the application owner check the logs for more information.
57 | 58 |