{"id":13394921,"url":"https://github.com/markets/maily","last_synced_at":"2025-05-15T07:03:32.171Z","repository":{"id":10804585,"uuid":"13077357","full_name":"markets/maily","owner":"markets","description":"📫 Rails Engine to preview emails in the browser","archived":false,"fork":false,"pushed_at":"2024-03-17T18:30:10.000Z","size":1020,"stargazers_count":707,"open_issues_count":2,"forks_count":32,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-05-15T07:02:09.823Z","etag":null,"topics":["email-delivery","email-preview","hooks","rails","rails-engine","ruby","rubygem"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/maily","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markets.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"support/images/logo.png","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-09-24T21:42:17.000Z","updated_at":"2025-05-13T04:16:13.000Z","dependencies_parsed_at":"2024-06-19T02:50:13.835Z","dependency_job_id":"b43edc50-7959-4b38-a0d9-63d1f144728b","html_url":"https://github.com/markets/maily","commit_stats":{"total_commits":169,"total_committers":11,"mean_commits":"15.363636363636363","dds":"0.12426035502958577","last_synced_commit":"481f5143d14c0a01a4000da7a3a574bab1449577"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markets%2Fmaily","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markets%2Fmaily/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markets%2Fmaily/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markets%2Fmaily/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markets","download_url":"https://codeload.github.com/markets/maily/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254291961,"owners_count":22046424,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["email-delivery","email-preview","hooks","rails","rails-engine","ruby","rubygem"],"created_at":"2024-07-30T17:01:36.214Z","updated_at":"2025-05-15T07:03:32.101Z","avatar_url":"https://github.com/markets.png","language":"Ruby","funding_links":[],"categories":["Ruby","Email"],"sub_categories":[],"readme":"\u003cdiv\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/markets/maily/master/support/images/logo.png\"\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://rubygems.org/gems/maily\"\u003e\u003cimg src=\"https://img.shields.io/gem/v/maily.svg?style=flat-square\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/markets/maily/actions\"\u003e\u003cimg src=\"https://github.com/markets/maily/workflows/CI/badge.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://codeclimate.com/github/markets/maily/maintainability\"\u003e\u003cimg src=\"https://api.codeclimate.com/v1/badges/fff01b2137fd73070b14/maintainability\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/markets/maily/blob/master/MIT-LICENSE\"\u003e\u003cimg alt=\"GitHub\" src=\"https://img.shields.io/github/license/markets/maily.svg?style=flat-square\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\nMaily is a Rails Engine to manage, test and navigate through all your email templates of your app, being able to preview them directly in your browser.\n\nMaily automatically picks up all your emails and make them accessible from a kind of dashboard.\n\n## Features:\n\n* Mountable engine\n* Visual preview in the browser (attachments as well)\n* Template edition (only in development)\n* Email delivery\n* Easy way (aka `Hooks`) to define and customize data for emails\n* Email versions\n* Flexible authorization system\n* Minimalistic and clean interface\n* Generator to handle a comfortable installation\n\n![](support/images/screenshot.png)\n\n## Installation\n\nAdd this line to your `Gemfile` and then run `bundle install`:\n\n```ruby\ngem 'maily'\n```\n\nRun generator:\n\n```\n\u003e rails g maily:install\n```\n\nThis generator runs some tasks for you:\n\n* Mounts the engine (to `/maily` by default) in your routes\n* Adds an initializer (into `config/initializers/maily.rb`) to customize some settings\n* Adds a file (into `lib/maily_hooks.rb`) to define hooks\n\n## Initialization and configuration\n\nYou should use the `setup` method to configure and customize `Maily` settings:\n\n ```ruby\n# config/initializers/maily.rb\n\nMaily.setup do |config|\n  # On/off engine\n  # config.enabled = !Rails.env.production?\n\n  # Allow templates edition\n  # config.allow_edition = !Rails.env.production?\n\n  # Allow deliveries\n  # config.allow_delivery = !Rails.env.production?\n\n  # Your application available_locales (or I18n.available_locales) by default\n  # config.available_locales = [:en, :es, :pt, :fr]\n\n  # Run maily under different controller ('ActionController::Base' by default)\n  # config.base_controller = '::AdminController'\n\n  # Configure hooks path\n  # config.hooks_path = 'lib/maily_hooks.rb'\n\n  # Http basic authentication (nil by default)\n  # config.http_authorization = { username: 'admin', password: 'secret' }\n\n  # Customize welcome message\n  # config.welcome_message = \"Welcome to our email testing platform. If you have any problem, please contact support team at support@example.com.\"\nend\n```\n\nYou can use the following format too:\n\n```ruby\nMaily.enabled = ENV['MAILY_ENABLED']\nMaily.allow_edition = false\n```\n\n### Templates edition (`allow_edition` option)\n\nThis feature was designed for the `development` environment. Since it's based on just a file edition, and while running in `production` mode, code is not reloaded between requests, Rails doesn't take into account your changes (without restarting the server). Actually, allowing arbitrary Ruby code evaluation is potentially dangerous, and that's not a good idea in `production`.\n\nSo, template edition is not allowed outside of the `development` environment.\n\n## Hooks\n\nMost of emails need to populate some data to consume it and do interesting things. Hooks are used to define this data via a little DSL. Hooks also accept \"callable\" objects to *lazy* load variables/data, so each email will evaluate its hooks on demand. Example:\n\n```ruby\n# lib/maily_hooks.rb\n\nuser = User.new(email: 'user@example.com')\nlazy_user = -\u003e { User.with_comments.first } # callable object, lazy evaluation\ncomment = Struct.new(:body).new('Lorem ipsum') # stub way\nservice = FactoryGirl.create(:service) # using fixtures with FactoryGirl\n\nMaily.hooks_for('Notifier') do |mailer|\n  mailer.register_hook(:welcome, user, template_path: 'users')\n  mailer.register_hook(:new_comment, lazy_user, comment)\nend\n\nMaily.hooks_for('PaymentNotifier') do |mailer|\n  mailer.register_hook(:invoice, user, service)\nend\n```\n\nNote that you are able to override the `template_path` and the `template_name` like can be done in Rails. You must pass these options as a hash and last argument:\n\n```ruby\nMaily.hooks_for('YourMailerClass') do |mailer|\n  mailer.register_hook(:a_random_email, template_path: 'notifications')\n  mailer.register_hook(:another_email, template_name: 'email_base')\nend\n```\n\n### Email versions\n\nYou can add versions for special emails. This is useful in some cases where template content depends on the parameters you provide, for instance, a welcome message for trial accounts and gold accounts.\n\n```ruby\nfree_trial_account = -\u003e { Account.free_trial.first }\ngold_account = -\u003e { Account.gold.first }\n\nMaily.hooks_for('Notifier') do |mailer|\n  mailer.register_hook(:welcome, free_trial_account, version: 'Free trial account')\n  mailer.register_hook(:welcome, gold_account, version: 'Gold account')\nend\n```\n\n### Email description\n\nYou can add a description to any email and it will be displayed along with its preview. This is useful in some cases like: someone from another team, for example, a marketing specialist, visiting Maily to review some texts and images; they can easily understand when this email is sent by the system.\n\n```ruby\nMaily.hooks_for('BookingNotifier') do |mailer|\n  mailer.register_hook(:accepted, description: \"This email is sent when a reservation has been accepted by the system.\" )\nend\n```\n\n### Hide emails\n\nYou are also able to hide emails:\n\n```ruby\nMaily.hooks_for('Notifier') do |mailer|\n  mailer.hide_email(:sensible_email, :secret_email)\nend\n```\n\n### Use `params`\n\nSupport for [`ActionMailer::Parameterized`](https://api.rubyonrails.org/classes/ActionMailer/Parameterized.html) is possible via `with_params` hash:\n\n```ruby\nmessage = -\u003e { 'Hello!' }\n\nMaily.hooks_for('Notifier') do |mailer|\n  mailer.register_hook(:new_message, with_params: { message: message })\nend\n```\n\n### External emails\n\nIf you want to register and display in the UI, emails from external sources, like for example a gem, you can do it by adding a hook. Example:\n\n```ruby\nMaily.hooks_for('Devise::Mailer') do |mailer|\n  mailer.hide_email(:unlock_instructions)\n\n  mailer.register_hook(:reset_password_instructions, user, 'random_token')\n  mailer.register_hook(:confirmation_instructions, user, 'random_token')\n  mailer.register_hook(:password_change, user)\nend\n```\n\n## Authorization\n\nBasically, you have 2 ways to restrict access to the `Maily` section. You can even combine both.\n\n### Custom base controller\n\nBy default `Maily` runs under `ActionController::Base`, but you are able to customize that parent controller (`Maily.base_controller` option) in order to achieve (using, for example, `before_action` blocks) a kind of access control system. For example, set a different base controller:\n\n```ruby\nMaily.base_controller = '::SuperAdminController'\n```\n\nAnd then write your own authorization rules in this defined controller:\n\n```ruby\nclass SuperAdminController \u003c ActionController::Base\n  before_action :maily_authorized?\n\n  private\n\n  def maily_authorized?\n    current_user.admin? || raise(\"You don't have access to this section!\")\n  end\nend\n```\n\n### HTTP basic authentication\n\nYou can also authorize yours users via HTTP basic authentication, simply use this option:\n\n```ruby\nMaily.http_authorization = { username: 'admin', password: 'secret' }\n```\n\n## Notes\n\nRails 4.1 introduced a built-in mechanism to preview the application emails. It is in fact, a port of [basecamp/mail_view](https://github.com/basecamp/mail_view) gem to the core.\n\nAlternatively, there are more gems out there to get a similar functionality, but with different approaches and features. Like for example: [ryanb/letter_opener](https://github.com/ryanb/letter_opener), [sj26/mailcatcher](https://github.com/sj26/mailcatcher) or [glebm/rails_email_preview](https://github.com/glebm/rails_email_preview).\n\n## Development\n\nAny kind of feedback, bug report, idea or enhancement are really appreciated :tada:\n\nTo contribute, just fork the repo, hack on it and send a pull request. Don't forget to add tests for behaviour changes and run the test suite:\n\n```\n\u003e bundle exec rspec\n```\n\nRun the test suite against all supported versions:\n\n```\n\u003e bundle exec appraisal install\n\u003e bundle exec appraisal rspec\n```\n\nRun specs against specific version:\n\n```\n\u003e bundle exec appraisal rails-6.0 rspec\n```\n\n### Demo\n\nStart a sample Rails app ([source code](spec/dummy)) with `Maily` integrated:\n\n```\n\u003e bundle exec rake web # PORT=4000 (default: 3000)\n```\n\n## License\n\nCopyright (c) Marc Anguera. Maily is released under the [MIT](MIT-LICENSE) License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkets%2Fmaily","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkets%2Fmaily","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkets%2Fmaily/lists"}