{"id":13462982,"url":"https://github.com/pboling/sanitize_email","last_synced_at":"2025-05-16T14:06:46.383Z","repository":{"id":449127,"uuid":"72127","full_name":"pboling/sanitize_email","owner":"pboling","description":"An Email Condom for your Ruby Server","archived":false,"fork":false,"pushed_at":"2025-05-08T19:09:38.000Z","size":659,"stargazers_count":169,"open_issues_count":1,"forks_count":34,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-05-08T20:24:17.703Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://railsbling.com/sanitize_email/","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/pboling.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["pboling"],"patreon":"galtzo","ko_fi":"pboling","liberapay":"pboling","issuehunt":"pboling"}},"created_at":"2008-11-05T22:51:48.000Z","updated_at":"2025-05-08T19:09:02.000Z","dependencies_parsed_at":"2023-07-05T14:56:07.035Z","dependency_job_id":"e599036b-7ec1-4780-8493-a71457cc895c","html_url":"https://github.com/pboling/sanitize_email","commit_stats":{"total_commits":376,"total_committers":29,"mean_commits":12.96551724137931,"dds":"0.28457446808510634","last_synced_commit":"4e05bfbd4c6ebdb481506ffa32091ad97c486939"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pboling%2Fsanitize_email","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pboling%2Fsanitize_email/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pboling%2Fsanitize_email/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pboling%2Fsanitize_email/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pboling","download_url":"https://codeload.github.com/pboling/sanitize_email/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254544146,"owners_count":22088807,"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":[],"created_at":"2024-07-31T13:00:43.324Z","updated_at":"2025-05-16T14:06:46.356Z","avatar_url":"https://github.com/pboling.png","language":"Ruby","funding_links":["https://github.com/sponsors/pboling","https://patreon.com/galtzo","https://ko-fi.com/pboling","https://liberapay.com/pboling","https://issuehunt.io/r/pboling","https://liberapay.com/pboling/donate","https://polar.sh/pboling","https://ko-fi.com/O5O86SNP4","https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte\u0026emoji=\u0026slug=pboling\u0026button_colour=FFDD00\u0026font_colour=000000\u0026font_family=Cookie\u0026outline_colour=000000\u0026coffee_colour=ffffff","https://www.buymeacoffee.com/pboling"],"categories":["Communication","Ruby"],"sub_categories":["E-Mail Preview"],"readme":"# sanitize_email\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)\n[![Version](https://img.shields.io/gem/v/sanitize_email.svg)](https://rubygems.org/gems/sanitize_email)\n[![Downloads Today](https://img.shields.io/gem/rd/sanitize_email.svg)](https://github.com/pboling/sanitize_email)\n[![Depfu][🔑depfui]][🔑depfu]\n[![CodeCov][🖇codecov-img♻️]][🖇codecov]\n[![Test Coverage][🔑cc-covi]][🔑cc-cov]\n[![Maintainability][🔑cc-mnti]][🔑cc-mnt]\n[![CI Supported Build][🚎s-wfi]][🚎s-wf]\n[![CI Unsupported Build][🚎us-wfi]][🚎us-wf]\n[![CI Style Build][🚎st-wfi]][🚎st-wf]\n[![CI Coverage Build][🚎cov-wfi]][🚎cov-wf]\n[![CI Heads Build][🚎hd-wfi]][🚎hd-wf]\n[![CI Ancient Build][🚎an-wfi]][🚎an-wf]\n\n[🖇codecov-img♻️]: https://codecov.io/gh/pboling/sanitize_email/graph/badge.svg?token=selEoMrZzA\n[🖇codecov]: https://codecov.io/gh/pboling/sanitize_email\n[🚎s-wf]: https://github.com/pboling/sanitize_email/actions/workflows/supported.yml\n[🚎s-wfi]: https://github.com/pboling/sanitize_email/actions/workflows/supported.yml/badge.svg\n[🚎us-wf]: https://github.com/pboling/sanitize_email/actions/workflows/unsupported.yml\n[🚎us-wfi]: https://github.com/pboling/sanitize_email/actions/workflows/unsupported.yml/badge.svg\n[🚎st-wf]: https://github.com/pboling/sanitize_email/actions/workflows/style.yml\n[🚎st-wfi]: https://github.com/pboling/sanitize_email/actions/workflows/style.yml/badge.svg\n[🚎cov-wf]: https://github.com/pboling/sanitize_email/actions/workflows/coverage.yml\n[🚎cov-wfi]: https://github.com/pboling/sanitize_email/actions/workflows/coverage.yml/badge.svg\n[🚎hd-wf]: https://github.com/pboling/sanitize_email/actions/workflows/heads.yml\n[🚎hd-wfi]: https://github.com/pboling/sanitize_email/actions/workflows/heads.yml/badge.svg\n[🚎an-wf]: https://github.com/pboling/sanitize_email/actions/workflows/ancient.yml\n[🚎an-wfi]: https://github.com/pboling/sanitize_email/actions/workflows/ancient.yml/badge.svg\n\n-----\n\n[![Liberapay Patrons][⛳liberapay-img]][⛳liberapay]\n[![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor]\n[![Polar Shield][🖇polar-img]][🖇polar]\n[![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi]\n[![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]\n\n[⛳liberapay-img]: https://img.shields.io/liberapay/patrons/pboling.svg?logo=liberapay\n[⛳liberapay]: https://liberapay.com/pboling/donate\n[🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social\u0026logo=github\n[🖇sponsor]: https://github.com/sponsors/pboling\n[🖇polar-img]: https://polar.sh/embed/seeks-funding-shield.svg?org=pboling\n[🖇polar]: https://polar.sh/pboling\n[🖇kofi-img]: https://img.shields.io/badge/buy%20me%20coffee-donate-yellow.svg\n[🖇kofi]: https://ko-fi.com/O5O86SNP4\n[🖇patreon-img]: https://img.shields.io/badge/patreon-donate-yellow.svg\n[🖇patreon]: https://patreon.com/galtzo\n\n[comment]: \u003c\u003e ( 🔑 KEYED LINKS )\n\n[🔑cc-mnt]: https://codeclimate.com/github/pboling/sanitize_email/maintainability\n[🔑cc-mnti]: https://api.codeclimate.com/v1/badges/65af4948d859903a0372/maintainability\n[🔑cc-cov]: https://codeclimate.com/github/pboling/sanitize_email/test_coverage\n[🔑cc-covi]: https://api.codeclimate.com/v1/badges/65af4948d859903a0372/test_coverage\n[🔑depfu]: https://depfu.com/github/pboling/sanitize_email\n[🔑depfui]: https://badges.depfu.com/badges/bba430e8f19a2ba3273fb20d5e8c82d6/count.svg\n\nThis gem allows you to override your mail delivery settings, globally or in a local context.\nIt is like a Ruby encrusted condom for your email server,\njust in case it decides to have intercourse with other servers via sundry mail protocols.\n\nSeriously though, this gem solves similar problems as the excellent [mailcatcher](https://mailcatcher.me/) gem,\nand `mailcatcher` solves those problems far more easily.\n\nIn addition, this gem solves problems that `mailcatcher` does not solve.  I recommend using both!\n\nTo make an analogy, `mailcatcher` is akin to `webmock`, entirely preventing interaction with your real live mail server,\nwhile this gem allows you to effectively use your real live (production!) mail server, while\nintercepting and modifying recipients on the way out, so that testing emails go to safe locations.\n\nIt is a bit like using the \"test\" Visa credit card number `4701322211111234` with a real payment gateway.\n\n## Encryption\n\nMaking special note of this use case because it is important for companies working on HIPAA-compliant products.\nWhen you are sending emails through an encrypted email provider, e.g. [Paubox](https://www.paubox.com/),\ntesting your email in the aforementioned `mailcatcher` may not be enough.\n\nIf you want to test all the way through Paubox's system, but have the email go to a safe testing account address,\nthen this is the gem for you.\n\n## Compatibility\n\n- ⚙️ Compatible with all versions of Ruby \u003e= 2.3, plus JRuby and Truffleruby.\n- ⚙️ Compatible with all Ruby web Frameworks (Hanami, Roda, Sinatra, Rails).\n- ⚙️ Compatible with all versions of Rails from 3.0 - 7.1+.\n- ⚙️ Compatible with scripted usage of Mail gem outside a web framework.\n- ⚙️ Compatible with [`sendgrid-actionmailer`](https://github.com/eddiezane/sendgrid-actionmailer)'s support for personalizations, and will override email addresses there according to the configuration.\n- ⚙️ If this gem is not compatible with your use case, and you'd like it to be, I'd like to hear about it!\n\nIt was a slog getting (very nearly) the entire compatibility matrix working with Github Actions, [appraisal](https://github.com/thoughtbot/appraisal), and [combustion](https://github.com/pat/combustion), and I'm very interested in hearing about ways to improve it!\n\n## 🛞 DVCS\n\nThis project does not trust any one version control system,\nso it abides the principles of [\"Distributed Version Control Systems\"][💎d-in-dvcs]\n\nFind this project on:\n\n| Any            | Of               | These          | DVCS           |\n|----------------|------------------|----------------|----------------|\n| [🐙hub][🐙hub] | [🧊berg][🧊berg] | [🛖hut][🛖hut] | [🧪lab][🧪lab] |\n\n[comment]: \u003c\u003e ( DVCS LINKS )\n\n[💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/\n\n[🧊berg]: https://codeberg.org/pboling/sanitize_email\n[🐙hub]: https://gitlab.com/pboling/sanitize_email\n[🛖hut]: https://sr.ht/~galtzo/pboling/sanitize_email\n[🧪lab]: https://gitlab.com/pboling/sanitize_email\n\n\u003c!--\nNumbering rows and badges in each row as a visual \"database\" lookup,\n    as the table is extremely dense, and it can be very difficult to find anything\nPutting one on each row here, to document the emoji that should be used, and for ease of copy/paste.\n\nrow #s:\n1️⃣\n2️⃣\n3️⃣\n4️⃣\n5️⃣\n6️⃣\n7️⃣\n\nbadge #s:\n⛳️\n🖇\n🏘\n🚎\n🖐\n🧮\n📗\n\nappended indicators:\n♻️ / 🔑 - Tagged URLs need to be updated from SAAS integration. Find / Replace is insufficient.\n--\u003e\n\n|     | Project                        | bundle add sanitize_email                                                                                                                                                                                                                                                                                                                                                                                                                           |\n|:----|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| 1️⃣ | name, license, docs, standards | [![RubyGems.org][⛳️name-img]][⛳️gem] [![License: MIT][🖇src-license-img]][🖇src-license] [![RubyDoc.info][🚎yard-img]][🚎yard] [![YARD Documentation](http://inch-ci.org/github/pboling/sanitize_email.svg)][🚎yard] [![SemVer 2.0.0][🧮semver-img]][🧮semver] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog]                                                                                                                  |\n| 2️⃣ | version \u0026 activity             | [![Gem Version][⛳️version-img]][⛳️gem] [![Total Downloads][🖇DL-total-img]][⛳️gem] [![Download Rank][🏘DL-rank-img]][⛳️gem] [![Source Code][🚎src-main-img]][🚎src-main] [![Open PRs][🖐prs-o-img]][🖐prs-o] [![Closed PRs][🧮prs-c-img]][🧮prs-c]                                                                                                                                                                                                  |\n| 3️⃣ | maintenance \u0026 linting          | [![Helpers][🖇triage-help-img]][🖇triage-help] [![Depfu][🔑depfui]][🔑depfu] [![Contributors][🚎contributors-img]][🚎contributors]                                                                                                                                                                                                                                                                            |\n| 4️⃣ | coverage \u0026 security            | [![CodeCov][🖇codecov-img♻️]][🖇codecov] [![Coveralls][🏘coveralls-img]][🏘coveralls] [![Security Policy][🚎sec-pol-img]][🚎sec-pol] [![CodeQL][🖐codeQL-img]][🖐codeQL]                                                                                                                                                                                                                                |\n| 5️⃣ | resources                      | [![Get help on Codementor][🖇codementor-img]][🖇codementor] [![Chat][🏘chat-img]][🏘chat] [![Blog][🚎blog-img]][🚎blog] [![Wiki][🖐wiki-img]][🖐wiki]                                                                                                                                                                                                                                                                                               |\n| 6️⃣ | `...` 💖                       | [![Liberapay Patrons][⛳liberapay-img]][⛳liberapay] [![Sponsor Me][🖇sponsor-img]][🖇sponsor] [![Follow Me on LinkedIn][🖇linkedin-img]][🖇linkedin] [![Find Me on WellFound:][✌️wellfound-img]][✌️wellfound] [![Find Me on CrunchBase][💲crunchbase-img]][💲crunchbase] [![My LinkTree][🌳linktree-img]][🌳linktree] [![Follow Me on Ruby.Social][🐘ruby-mast-img]][🐘ruby-mast] [![Tweet @ Peter][🐦tweet-img]][🐦tweet] [💻][coderme] [🌏][aboutme] |\n\n\u003c!--\nThe link tokens in the following sections should be kept ordered by the row and badge numbering scheme\n--\u003e\n\n\u003c!-- 1️⃣ name, license, docs --\u003e\n[⛳️gem]: https://rubygems.org/gems/sanitize_email\n[⛳️name-img]: https://img.shields.io/badge/name-sanitize__email-brightgreen.svg?style=flat\n[🖇src-license]: https://opensource.org/licenses/MIT\n[🖇src-license-img]: https://img.shields.io/badge/License-MIT-green.svg\n[🚎yard]: https://www.rubydoc.info/gems/sanitize_email\n[🚎yard-img]: https://img.shields.io/badge/documentation-rubydoc-brightgreen.svg?style=flat\n[🧮semver]: http://semver.org/\n[🧮semver-img]: https://img.shields.io/badge/semver-2.0.0-FFDD67.svg?style=flat\n[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/\n[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat\n\n\u003c!-- 2️⃣ version \u0026 activity --\u003e\n[⛳️version-img]: http://img.shields.io/gem/v/sanitize_email.svg\n[🖇DL-total-img]: https://img.shields.io/gem/dt/sanitize_email.svg\n[🏘DL-rank-img]: https://img.shields.io/gem/rt/sanitize_email.svg\n[🚎src-main]: https://gitlab.com/pboling/sanitize_email\n[🚎src-main-img]: https://img.shields.io/badge/source-gitlab-brightgreen.svg?style=flat\n[🖐prs-o]: https://gitlab.com/pboling/sanitize_email/-/merge_requests\n[🖐prs-o-img]: https://img.shields.io/github/issues-pr/pboling/sanitize_email\n[🧮prs-c]: https://github.com/pboling/sanitize_email/pulls?q=is%3Apr+is%3Aclosed\n[🧮prs-c-img]: https://img.shields.io/github/issues-pr-closed/pboling/sanitize_email\n\n\u003c!-- 3️⃣ maintenance \u0026 linting --\u003e\n[🖇triage-help]: https://www.codetriage.com/pboling/sanitize_email\n[🖇triage-help-img]: https://www.codetriage.com/pboling/sanitize_email/badges/users.svg\n[🚎contributors]: https://gitlab.com/pboling/sanitize_email/-/graphs/main\n[🚎contributors-img]: https://img.shields.io/github/contributors-anon/pboling/sanitize_email\n\n\u003c!-- 4️⃣ coverage \u0026 security --\u003e\n[🖇codecov-img♻️]: https://codecov.io/gh/pboling/sanitize_email/graph/badge.svg?token=Joire8DbSW\n[🖇codecov]: https://codecov.io/gh/pboling/sanitize_email\n[🏘coveralls]: https://coveralls.io/github/pboling/sanitize_email?branch=main\n[🏘coveralls-img]: https://coveralls.io/repos/github/pboling/sanitize_email/badge.svg?branch=main\n[🚎sec-pol]: https://gitlab.com/pboling/sanitize_email/-/blob/main/SECURITY.md\n[🚎sec-pol-img]: https://img.shields.io/badge/security-policy-brightgreen.svg?style=flat\n[🖐codeQL]: https://github.com/pboling/sanitize_email/security/code-scanning\n[🖐codeQL-img]: https://github.com/pboling/sanitize_email/actions/workflows/codeql-analysis.yml/badge.svg\n\n\u003c!-- 5️⃣ resources --\u003e\n[🖇codementor]: https://www.codementor.io/peterboling?utm_source=github\u0026utm_medium=button\u0026utm_term=peterboling\u0026utm_campaign=github\n[🖇codementor-img]: https://cdn.codementor.io/badges/get_help_github.svg\n[🏘chat]: https://gitter.im/pboling/sanitize_email\n[🏘chat-img]: https://img.shields.io/gitter/room/pboling/sanitize_email.svg\n[🚎blog]: http://www.railsbling.com/tags/sanitize_email/\n[🚎blog-img]: https://img.shields.io/badge/blog-railsbling-brightgreen.svg?style=flat\n[🖐wiki]: https://gitlab.com/pboling/sanitize_email/-/wikis/home\n[🖐wiki-img]: https://img.shields.io/badge/wiki-examples-brightgreen.svg?style=flat\n\n\u003c!-- 6️⃣ spread 💖 --\u003e\n[🐦tweet-img]: https://img.shields.io/twitter/follow/galtzo.svg?style=social\u0026label=Follow%20%40galtzo\n[🐦tweet]: http://twitter.com/galtzo\n[🚎blog]: http://www.railsbling.com/tags/sanitize_email/\n[🚎blog-img]: https://img.shields.io/badge/blog-railsbling-brightgreen.svg?style=flat\n[🖇linkedin]: http://www.linkedin.com/in/peterboling\n[🖇linkedin-img]: https://img.shields.io/badge/PeterBoling-blue?style=plastic\u0026logo=linkedin\n[✌️wellfound]: https://angel.co/u/peter-boling\n[✌️wellfound-img]: https://img.shields.io/badge/peter--boling-orange?style=plastic\u0026logo=wellfound\n[💲crunchbase]: https://www.crunchbase.com/person/peter-boling\n[💲crunchbase-img]: https://img.shields.io/badge/peter--boling-purple?style=plastic\u0026logo=crunchbase\n[🐘ruby-mast]: https://ruby.social/@galtzo\n[🐘ruby-mast-img]: https://img.shields.io/mastodon/follow/109447111526622197?domain=https%3A%2F%2Fruby.social\u0026style=plastic\u0026logo=mastodon\u0026label=Ruby%20%40galtzo\n[🌳linktree]: https://linktr.ee/galtzo\n[🌳linktree-img]: https://img.shields.io/badge/galtzo-purple?style=plastic\u0026logo=linktree\n\n\u003c!-- Maintainer Contact Links --\u003e\n[aboutme]: https://about.me/peter.boling\n[coderme]: https://coderwall.com/Peter%20Boling\n\n## Summary\n\nIt's particularly helpful when you want to prevent the delivery of email (e.g. in development/test environments) or alter the to/cc/bcc (e.g. in staging or demo environments) of all email generated from your application.\n\n* compatible without Rails!  Can work with just the `mail` gem.\n* compatible with Rails \u003e= 3.0.  See gem versions 1.x for older versions of Rails.\n* compatible with Ruby \u003e= 2.3.  See gem versions 1.x for older versions of Ruby.\n* compatible with any Ruby app with a mail handler that uses the `register_interceptor` API (a la ActionMailer and `mail` gems)\n* configure it and forget it\n* little configuration required\n* solves common problems in ruby web applications that use email\n* provides test helpers and spec matchers to assist with testing email content delivery\n\n## Working Locally with Production Data\n\n1. Have a production site with live data\n2. Dump the live data and securely transfer it to another machine (e.g. rync -e ssh)\n3. Import it into a development database\n4. Test features which send out email (registration/signup, order placement, etc.)\n5. Emails get sent (in real-life!) but to sanitized email recipients\n6. Verify what they look like when sent\n7. Iterate on email content design\n8. No risk of emailing production addresses\n\n## Re-routing Email on a Staging or QA Server\n\nAnother very important use case for me is to transparently re-route email generated from a staging or QA server to an appropriate person.  For example, it's common for us to set up a staging server for a client to use to view our progress and test out new features.  It's important for any email that is generated from our web application be delivered to the client's inbox so that they can review the content and ensure that it's acceptable.  `dotenv` or `direnv` allows each developer to configure the local behavior specifically for them via ENV vars.\n\n## Testing Email from a Hot Production Server\n\nIf you install this gem on a production server (which I don't always do), you can load up script/console and override the to/cc/bcc on all emails for the duration of your console session.  This allows you to poke and prod a live production instance, and route all email to your own inbox for inspection.  The best part is that this can all be accomplished without changing a single line of your application code.\n\n## Monitoring all email sent by server to a backup account\n\nYou may want to add a BCC automatically (e.g. to account-history@my-company.com) to every email sent by your system, for customer service purposes, and this gem allows that.  Note that this may not be a good idea for all systems, for many reasons, e.g security!\n\n## Using with a test suite as an alternative to the heavy email_spec\n\n[email_spec](https://github.com/bmabey/email-spec) is a great gem, with awesome rspec matchers and helpers, but it has an undeclared dependency on ActionMailer. Sad face.\n\nSanitizeEmail comes with some lightweight RspecMatchers covering most of what email_spec can do.  It will help you test email functionality.  It is useful when you are creating a gem to handle email features, or are writing a simple Ruby script, and don't want to pull in le Rails.  SanitizeEmail has two dependencies, `mail` gem, and `version_gem`.  Your Mail system just needs to conform to `mail` gem's `register_interceptor` API.\n\n## Install Like a Boss\n\nIn Gemfile:\n\n       gem 'sanitize_email'\n\nThen:\n\n       bundle install\n\n## Setup with Ruby\n\n_keep scrolling for Rails, but read this for a better understanding of Magic_\n\nThere are three ways SanitizeEmail can be turned on; in order of precedence they are:\n\n1. Only useful for local context.  Inside a method where you will be sending an email, set `SanitizeEmail.force_sanitize = true` just prior to delivering it.  Also useful in the console.\n\n        SanitizeEmail.force_sanitize = true # by default it is nil\n\n2. If SanitizeEmail seems to not be sanitizing you have probably not registered the interceptor.  SanitizeEmail tries to do this for you. *Note*: If you are working in an environment that has a Mail or Mailer class that uses the register_interceptor API, the interceptor will already have been registered by SanitizeEmail:\n\n        # The gem will probably have already done this for you, but some really old versions of Rails may need you to do this manually:\n        Mail.register_interceptor(SanitizeEmail::Bleach)\n\n   Once registered, SanitizeEmail needs to be engaged:\n\n        # in config/initializers/sanitize_email.rb\n        SanitizeEmail::Config.configure { |config| config[:engage] = true }\n\n3. If you don't need to compute anything, then don't use this option, go with the previous option.\n\n        SanitizeEmail::Config.configure { |config| config[:activation_proc] = proc { true } } # by default :activation_proc is false\n\n### Examples\n\n#### Only allow email to a specific domain\n\nThis works by ensuring that all recipients have the \"allowed\" domain.\nIn other words, none of the recipients have a domain other than the allowed domain.\n\n        allowed_domain = \"example.com\"\n        # NOTE: you may need to check CC and BCC also, depending on your use case...\n        SanitizeEmail::Config.configure do |config|\n          config[:activation_proc] =\n            -\u003e(message) do\n              !Array(message.to).any? { |recipient| Mail::Address.new(recipient).domain != allowed_domain }\n            end\n        end\n\n### Notes\n\nNumber 1, above, is the method used by the SanitizeEmail.sanitary block.\nIf installed but not configured, sanitize_email DOES NOTHING.  Until configured the defaults leave it turned off.\n\n### Troubleshooting\n\nIMPORTANT: You may need to setup your own register_interceptor.  If sanitize_email doesn't seem to be working for you find your Mailer/Mail class and try this:\n\n        # in config/initializers/sanitize_email.rb\n        Mail.register_interceptor(SanitizeEmail::Bleach)\n        SanitizeEmail::Config.configure { |config| config[:engage] = true }\n\nIf that causes an error you will know why sanitize_email doesn't work.\nOtherwise it will start working according to the rest of the configuration.\n\n## Setup With Rails\n\nCreate an initializer, if you are using rails, or otherwise configure:\n\n        SanitizeEmail::Config.configure do |config|\n          config[:sanitized_to] = \"to@sanitize_email.org\"\n          config[:sanitized_cc] = \"cc@sanitize_email.org\"\n          config[:sanitized_bcc] = \"bcc@sanitize_email.org\"\n          # run/call whatever logic should turn sanitize_email on and off in this Proc:\n          config[:activation_proc] = proc { %w(development test).include?(Rails.env) }\n          config[:use_actual_email_prepended_to_subject] = true         # or false\n          config[:use_actual_environment_prepended_to_subject] = true   # or false\n          config[:use_actual_email_as_sanitized_user_name] = true       # or false\n        end\n\nKeep in mind, this is ruby (and possibly rails), so you can add conditionals or utilize different environment.rb files to customize these settings on a per-environment basis.\n\n## Override the override\n\nBut wait there's more:\n\nLet's say you have a method in your model that you can call to test the signup email. You want to be able to test sending it to any user at any time... but you don't want the user to ACTUALLY get the email, even in production. A dilemma, yes?  Not anymore!\n\nTo override the environment based switch use `force_sanitize`, which is normally `nil`, and ignored by default. When set to `true` or `false` it will turn sanitization on or off:\n\n       SanitizeEmail.force_sanitize = true\n\nWhen testing your email in a console, you can manipulate how email will be handled in this way.\n\nThere are also two methods that take a block and turn SanitizeEmail on or off (see section on Thread Safety below):\n\nRegardless of the Config settings of SanitizeEmail you can do a local override to force unsanitary email in any environment.\n\n       SanitizeEmail.unsanitary do\n         Mail.deliver do\n           from \"from@example.org\"\n           to \"to@example.org\" # Will actually be sent to the specified address, not sanitized\n           reply_to \"reply_to@example.org\"\n           subject \"subject\"\n         end\n       end\n\nRegardless of the Config settings of SanitizeEmail you can do a local override to send sanitary email in any environment.\nYou have access to all the same configuration options in the parameter hash as you can set in the actual\n`SanitizeEmail.configure` block.\n\n        SanitizeEmail.sanitary(sanitized_to: \"boo@example.com\") do # these config options are merged with the globals\n          Mail.deliver do\n            from \"from@example.org\"\n            to \"to@example.org\" # Will actually be sent to the override addresses, in this case: boo@example.com\n            reply_to \"reply_to@example.org\"\n            subject \"subject\"\n          end\n        end\n\n## Configuration Options\n\nAs used in the \"Description\" column below, `engaged` means: `SanitizeEmail.activate?(message) # =\u003e true`.\nThis happens in a few different ways, and two of them are in the config below (`engage` and `activation_proc`).\n\n| Option                                      | Type (Yard format)                   | Description                                                                                                                            |\n|---------------------------------------------|--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|\n| sanitized_to                                | [String, Array[String]]              | (when engaged) Override CC field with these addresses                                                                                  |\n| sanitized_cc                                | [String, Array[String]]              | (when engaged) Override CC field with these addresses                                                                                  |\n| sanitized_bcc                               | [String, Array[String]]              | (when engaged) Override BCC field with these addresses                                                                                 |\n| good_list                                   | [Array[String]]                      | (when engaged) Email addresses to allow to pass-through without overriding                                                             |\n| bad_list                                    | [Array[String]]                      | (when engaged) Email addresses to be removed from message's TO, CC, \u0026 BCC                                                              |\n| environment                                 | [String, #to_s, Proc, Lambda, #call] | (when engaged) The environment value to use wherever it is added to message (e.g. in the subject line)                                 |\n| use_actual_email_as_sanitized_user_name     | [Boolean]                            | (when engaged) Use \"real\" email address as username for sanitized email address (e.g. `\"real at example.com \u003csanitized@example.com\u003e\"`) |\n| use_actual_email_prepended_to_subject       | [Boolean]                            | (when engaged) Use \"real\" email address prepended to subject (e.g. `\"real at example.com Original Subject\"`)                           |\n| use_actual_environment_prepended_to_subject | [Boolean]                            | (when engaged) Use `environment` prepended to subject (e.g. `\"[[ STAGING ]] Original Subject\"`)                                        |\n| engage                                      | [Boolean, nil]                       | Boolean will turn engage or disengage this gem, while `nil` ignores this setting and instead checks `activation_proc`                  |\n| activation_proc                             | [Proc, Lambda, #call]                | When checked, due to `engage: nil`, the result will either engage or disengage this gem                                                |\n\n## Thread Safety\n\nSo long as you don't change the config after initializing it at runtime, you'll be fine.\nLike many Ruby tools' config objects, it is a single config object, shared by all threads.\nThe helpers like `sanitary`, `unsanitary`, `janitor`, and `force_sanitize`\nare intended to be used in single threaded environments,\nlike a test suite, or a console session.\n\nI doubt I'll ever have a need for runtime reconfiguration of the config,\nso I doubt I'll ever have a reason to make it \"more\" thread safe than it is now, but PRs are welcome!\n\n## Use sanitize_email in your test suite!\n\n### rspec\n\nIn your `spec_helper.rb`:\n\n\n       require \"sanitize_email\"\n       # rspec matchers are *not* loaded by default in sanitize_email, as it is not primarily a gem for test suites.\n       require \"sanitize_email/rspec_matchers\"\n\n       SanitizeEmail::Config.configure do |config|\n         config[:sanitized_to] = \"sanitize_email@example.org\"\n         config[:sanitized_cc] = \"sanitize_email@example.org\"\n         config[:sanitized_bcc] = \"sanitize_email@example.org\"\n         # run/call whatever logic should turn sanitize_email on and off in this Proc.\n         # config[:activation_proc] =      Proc.new { true }\n         # Since this configuration is *inside* the spec_helper, it might be assumed that we always want to sanitize.  If we don't want to it can be easily manipulated with SanitizeEmail.unsanitary and SanitizeEmail.sanitary block helpers.\n         # Thus instead of using the Proc (slower) we just engage it always:\n         config[:engage] = true\n         config[:use_actual_email_prepended_to_subject] = true         # or false\n         config[:use_actual_environment_prepended_to_subject] = true   # or false\n         config[:use_actual_email_as_sanitized_user_name] = true       # or false\n       end\n\n       # If your mail system is not one that sanitize_email automatically configures an interceptor for (ActionMailer, Mail)\n       # then you will need to do the equivalent for whatever Mail system you are using.\n\n       RSpec.configure do |config|\n         # ...\n         # From sanitize_email gem\n         config.include(SanitizeEmail::RspecMatchers)\n       end\n\n       context \"an email test\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should have_to(\"sanitize_email@example.org\") }\n       end\n\n#### have_* matchers\n\nThese will look for an email address in any of the following mail attributes:\n\n       [:from, :to, :cc, :bcc, :subject, :reply_to]\n\nExample:\n\n       context \"the subject line must have the email address sanitize_email@example.org\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should have_subject(\"sanitize_email@example.org\") }\n       end\n\n#### be_* matchers\n\nThese will look for a matching string in any of the following attributes:\n\n       [:from, :to, :cc, :bcc, :subject, :reply_to]\n\nExample:\n\n       context \"the subject line must have the string 'foobarbaz'\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should be_subject(\"foobarbaz\") }\n       end\n\n#### have_to_username matcher\n\nThe `username` in the `:to` field is when the `:to` field is formatted like this:\n\n`\"Peter Boling\" \u003csanitize_email@example.org\u003e`\n\nExample:\n\n       context \"the to field must have the username 'Peter Boling'\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should have_to_username(\"Peter Boling\") }\n       end\n\n#### have_sanitized_to_header matcher\n\nMatches any part of the value of the first sanitized to header (`\"X-Sanitize-Email-To\"`),\nwhich could be formatted like this:\n\n`\"Peter Boling\" \u003csanitize_email@example.org\u003e`\n\nNOTE: It won't match subsequent headers like `\"X-Sanitize-Email-To-2\"`, or `\"X-Sanitize-Email-To-3\"`.\n\nExample:\n\n       context \"the first 'X-Sanitize-Email-To' header must have the username 'Peter Boling'\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should have_sanitized_to_header(\"Peter Boling\") }\n       end\n\n#### have_cc_username matcher\n\nThe `username` in the `:cc` field is when the `:c` field is formatted like this:\n\n`\"Peter Boling\" \u003csanitize_email@example.org\u003e`\n\nExample:\n\n       context \"the cc field must have the username 'Peter Boling'\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should have_cc_username(\"Peter Boling\") }\n       end\n\n#### have_sanitized_cc_header matcher\n\nMatches any part of the value of the first sanitized cc header (`\"X-Sanitize-Email-Cc\"`),\nwhich could be formatted like this:\n\n`\"Peter Boling\" \u003csanitize_email@example.org\u003e`\n\nNOTE: It won't match subsequent headers like `\"X-Sanitize-Email-Cc-2\"`, or `\"X-Sanitize-Email-Cc-3\"`.\n\nExample:\n\n       context \"the first 'X-Sanitize-Email-Cc' header must have the username 'Peter Boling'\" do\n         subject { Mail.deliver(@message_hash) }\n         it { should have_sanitized_cc_header(\"Peter Boling\") }\n       end\n\n### non-rspec (Test::Unit, mini-test, etc)\n\nIn your setup file:\n\n       require \"sanitize_email\"\n       # test helpers are *not* loaded by default in sanitize_email, as it is not primarily a gem for test suites.\n       require \"sanitize_email/test_helpers\"\n\n       SanitizeEmail::Config.configure do |config|\n         config[:sanitized_to] = \"sanitize_email@example.org\"\n         config[:sanitized_cc] = \"sanitize_email@example.org\"\n         config[:sanitized_bcc] = \"sanitize_email@example.org\"\n         # run/call whatever logic should turn sanitize_email on and off in this Proc.\n         # config[:activation_proc] =      Proc.new { true }\n         # Since this configuration is *inside* the spec_helper, it might be assumed that we always want to sanitize.  If we don't want to it can be easily manipulated with SanitizeEmail.unsanitary and SanitizeEmail.sanitary block helpers.\n         # Thus instead of using the Proc (slower) we just engage it always:\n         config[:engage] = true\n         config[:use_actual_email_prepended_to_subject] = true         # or false\n         config[:use_actual_environment_prepended_to_subject] = true   # or false\n         config[:use_actual_email_as_sanitized_user_name] = true       # or false\n       end\n\n       # If your mail system is not one that sanitize_email automatically configures an interceptor for (ActionMailer, Mail)\n       # then you will need to do the equivalent for whatever Mail system you are using.\n\n       # You need to know what to do here... somehow get the methods into rhw scope of your tests.\n       # Something like this maybe?\n       include SanitizeEmail::TestHelpers\n       # Look here to see what it gives you:\n       # https://github.com/pboling/sanitize_email/blob/master/lib/sanitize_email/test_helpers.rb\n\n## Deprecations\n\nSometimes things get deprecated (meaning they still work, but are noisy about it).  If this happens to you, and you like your head in the sand, call this number:\n\n       SanitizeEmail::Deprecation.deprecate_in_silence = true\n\n## Authors\n\nPeter Boling is the original author of the code, and current maintainer.\n\nThanks to John Trupiano for turning Peter's original Rails plugin into the initial cut of this gem!\n\n## 🤝 Contributing\n\nSee [CONTRIBUTING.md][🤝contributing]\n\n[🤝contributing]: CONTRIBUTING.md\n\n### You can help!\n\nTake a look at the `reek` list which is the file called `REEK` and start fixing things.\n\nTo refresh the `reek` list:\n\n`bundle exec reek \u003e REEK`\n\nThen follow these instructions:\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Make some fixes.\n4. Commit your changes (`git commit -am 'Added some feature'`)\n5. Push to the branch (`git push origin my-new-feature`)\n6. Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.\n7. Create new Pull Request.\n\n## 🌈 Contributors\n\n[![Contributors][🌈contrib-rocks-img]][🐙hub-contrib]\n\nContributor tiles (GitHub only) made with [contributors-img][🌈contrib-rocks].\n\nLearn more about, or become one of, our 🎖 contributors on:\n\n| Any                                 | Of                                    | These                               | DVCS                                |\n|-------------------------------------|---------------------------------------|-------------------------------------|-------------------------------------|\n| [🐙hub contributors][🐙hub-contrib] | [🧊berg contributors][🧊berg-contrib] | [🛖hut contributors][🛖hut-contrib] | [🧪lab contributors][🧪lab-contrib] |\n\n[comment]: \u003c\u003e ( DVCS CONTRIB LINKS )\n\n[🌈contrib-rocks]: https://contrib.rocks\n[🌈contrib-rocks-img]: https://contrib.rocks/image?repo=pboling/sanitize_email\n\n[🧊berg-contrib]: https://codeberg.org/pboling/sanitize_email/activity\n[🐙hub-contrib]: https://github.com/pboling/sanitize_email/graphs/contributors\n[🛖hut-contrib]: https://git.sr.ht/~galtzo/sanitize_email/log/\n[🧪lab-contrib]: https://gitlab.com/pboling/sanitize_email/-/graphs/main?ref_type=heads\n\n## Star History\n\n\u003ca href=\"https://star-history.com/#pboling/sanitize_email\u0026Date\"\u003e\n \u003cpicture\u003e\n   \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=pboling/sanitize_email\u0026type=Date\u0026theme=dark\" /\u003e\n   \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=pboling/sanitize_email\u0026type=Date\" /\u003e\n   \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=pboling/sanitize_email\u0026type=Date\" /\u003e\n \u003c/picture\u003e\n\u003c/a\u003e\n\n## Running Specs\n\nThe basic compatibility matrix:\n\n       appraisal install\n       appraisal rake test\n\nNOTE: `appraisal install` uses the standard Gemfile, and thus adds a bunch of gems\nwe do not need in each of our appraisal gemfiles.\n\nInstead we can do one of:\n\n       BUNDLE_GEMFILE=gemfiles/vanilla.gemfile appraisal generate\n       BUNDLE_GEMFILE=gemfiles/vanilla.gemfile appraisal update\n\nNOTE: This results in bad paths to the gemspec from each of the appraisal `gemfiles/rails_*_*.gemfile` files.\n`gemspec path: \"../../\"` needs to be replaced with `gemspec path: \"../\"` in each Appraisal gemfile.\n\nIt is unlikely to be possible to install all of the supported Rubies \u0026 Railsies in a single container...\nSee the various github action workflows for more inspiration on running certain oldies.\n\n### Code Coverage\n\n[![Coverage Graph][🔑codecov-g]][🖇codecov]\n\n[🔑codecov-g]: https://codecov.io/gh/pboling/sanitize_email/graphs/tree.svg?token=Joire8DbSW\n\n## 🪇 Code of Conduct\n\nEveryone interacting in this project's codebases, issue trackers,\nchat rooms and mailing lists is expected to follow the [code of conduct][🪇conduct].\n\n[🪇conduct]: CODE_OF_CONDUCT.md\n\n## 📌 Versioning\n\nThis Library adheres to [Semantic Versioning 2.0.0][📌semver].\nViolations of this scheme should be reported as bugs.\nSpecifically, if a minor or patch version is released that breaks backward compatibility,\na new version should be immediately released that restores compatibility.\nBreaking changes to the public API will only be introduced with new major versions.\n\nTo get a better understanding of how SemVer is intended to work over a project's lifetime,\nread this article from the creator of SemVer:\n\n- [\"Major Version Numbers are Not Sacred\"][📌major-versions-not-sacred]\n\nAs a result of this policy, you can (and should) specify a dependency on these libraries using\nthe [Pessimistic Version Constraint][📌pvc] with two digits of precision.\n\nFor example:\n\n       spec.add_dependency(\"sanitize_email\", \"~\u003e 2.0\")\n\n[comment]: \u003c\u003e ( 📌 VERSIONING LINKS )\n\n[📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint\n[📌semver]: http://semver.org/\n[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html\n\n## References\n\n* [Source Code](http://github.com/pboling/sanitize_email)\n* [Gem Release Announcement](http://blog.smartlogicsolutions.com/2009/04/25/reintroducing-sanitize_email-work-with-production-email-without-fear/)\n* [Peter's Original Writeup](http://galtzo.blogspot.com/2008/11/sanitize-email-never-worry-about.html)\n* [Using sanitize_email to Preview HTML Emails Locally](http://blog.smartlogicsolutions.com/2009/04/30/using-sanitize-email-to-preview-html-emails-locally/)\n\n## 📄 License\n\nThe gem is available as open source under the terms of\nthe [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].\nSee [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].\n\n[comment]: \u003c\u003e ( 📄 LEGAL LINKS )\n\n[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year\n[📄license]: LICENSE.txt\n[📄license-ref]: https://opensource.org/licenses/MIT\n[📄license-img]: https://img.shields.io/badge/License-MIT-green.svg\n\n### © Copyright\n\n* Copyright (c) 2009 [John Trupiano](http://smartlogicsolutions.com/wiki/John_Trupiano) of [SmartLogic Solutions, LLC](http://www.smartlogicsolutions.com)\n* Copyright (c) 2008 - 2018, 2020, 2022, 2024 [Peter H. Boling][peterboling] of [Rails Bling][railsbling]\n\n[railsbling]: http://www.railsbling.com\n[peterboling]: http://www.peterboling.com\n\n## 🤑 One more thing\n\nYou made it to the bottom of the page,\nso perhaps you'll indulge me for another 20 seconds.\nI maintain many dozens of gems, including this one,\nbecause I want Ruby to be a great place for people to solve problems, big and small.\nPlease consider supporting my efforts via the giant yellow link below,\nor one of the others at the head of this README.\n\n[![Buy me a latte][🖇buyme-img]][🖇buyme]\n\n[🖇buyme-img]: https://img.buymeacoffee.com/button-api/?text=Buy%20me%20a%20latte\u0026emoji=\u0026slug=pboling\u0026button_colour=FFDD00\u0026font_colour=000000\u0026font_family=Cookie\u0026outline_colour=000000\u0026coffee_colour=ffffff\n[🖇buyme]: https://www.buymeacoffee.com/pboling\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpboling%2Fsanitize_email","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpboling%2Fsanitize_email","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpboling%2Fsanitize_email/lists"}