{"id":13507834,"url":"https://github.com/beam-community/bamboo","last_synced_at":"2025-12-12T00:30:55.970Z","repository":{"id":37677402,"uuid":"45436531","full_name":"beam-community/bamboo","owner":"beam-community","description":"Testable, composable, and adapter based Elixir email library for devs that love piping.","archived":false,"fork":false,"pushed_at":"2025-04-21T14:58:13.000Z","size":905,"stargazers_count":1938,"open_issues_count":4,"forks_count":333,"subscribers_count":34,"default_branch":"main","last_synced_at":"2025-05-11T20:41:54.992Z","etag":null,"topics":["bamboo","elixir","elixir-phoenix","email"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/bamboo","language":"Elixir","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/beam-community.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-11-03T02:30:34.000Z","updated_at":"2025-05-09T03:55:24.000Z","dependencies_parsed_at":"2023-02-16T21:30:53.345Z","dependency_job_id":"c513364b-6e1e-4060-ab2b-ae4f24e6508c","html_url":"https://github.com/beam-community/bamboo","commit_stats":{"total_commits":447,"total_committers":155,"mean_commits":"2.8838709677419354","dds":0.7986577181208054,"last_synced_commit":"acaa7c5419759dfb9ed253fce864e7fbd29cfe5e"},"previous_names":["thoughtbot/bamboo"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-community%2Fbamboo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-community%2Fbamboo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-community%2Fbamboo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-community%2Fbamboo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beam-community","download_url":"https://codeload.github.com/beam-community/bamboo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253933580,"owners_count":21986620,"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":["bamboo","elixir","elixir-phoenix","email"],"created_at":"2024-08-01T02:00:40.485Z","updated_at":"2025-12-12T00:30:55.928Z","avatar_url":"https://github.com/beam-community.png","language":"Elixir","readme":"![bamboo](https://user-images.githubusercontent.com/22394/39895001-b13a9c9a-5476-11e8-9c58-f5fc5f09b697.png)\n\n# Bamboo\n\n[![Build](https://github.com/beam-community/bamboo/actions/workflows/ci.yaml/badge.svg)](https://github.com/beam-community/bamboo/actions/workflows/ci.yaml)\n\n---\n\n**This README follows the main branch, which may not be the currently published version!** Use\n[the docs for the published version of Bamboo](https://hexdocs.pm/bamboo/readme.html).\n\n---\n\n**Bamboo is now maintained by the [BEAM Community](https://github.com/beam-community)!**\n\nThank you to [thoughtbot](https://thoughtbot.com) for creating and maintaining Bamboo for so long!\n\nFlexible and easy to use email for Elixir.\n\n- **Built-in support for popular mail delivery services**. Bamboo ships with\n  [adapters for several popular mail delivery services, including Mandrill,\n  Mailgun, and SendGrid][available-adapters]. It's also quite easy to write\n  your own delivery adapter if your platform isn't yet supported.\n- **Deliver emails in the background**. Most of the time you don't want or need\n  to wait for the email to send. Bamboo makes it easy with\n  `Mailer.deliver_later`.\n- **A functional approach to mail delivery**. Emails are created, manipulated,\n  and sent using plain functions. This makes composition a breeze and fits\n  naturally into your existing Elixir app.\n- **Unit test with ease**. Bamboo separates email creation and email delivery\n  allowing you to test by asserting against email fields without the need for\n  special functions.\n- **Dead-simple integration tests**. Bamboo provides helper functions to make\n  integration testing easy and robust.\n- **View sent emails during development**. Bamboo provides a plug you can use\n  in your router to view sent emails.\n- **Integrate with Phoenix out of the box**. Use Phoenix views and layouts to\n  make rendering email easy.\n\nSee the [docs] for the most up to date information.\n\nWe designed Bamboo to be simple and powerful. If you run into _anything_ that\nis less than exceptional, or you just need some help, please open an issue.\n\n## Installation\n\nTo install Bamboo, add it to your list of dependencies in `mix.exs`.\n\n```elixir\ndef deps do\n  [{:bamboo, \"~\u003e 2.3.0\"}]\nend\n```\n\nYou may also use the latest code available from master instead of a\npublished version in hex:\n\n```elixir\ndef deps do\n  [{:bamboo, github: \"beam-community/bamboo\"}]\nend\n```\n\nOnce you've added Bamboo to your list, update your dependencies by running:\n\n```sh\n$ mix deps.get\n```\n\nIf you are using Elixir \u003c 1.4, also ensure Bamboo is started alongside your\napplication:\n\n```elixir\ndef application do\n  [applications: [:bamboo]]\nend\n```\n\n## Getting Started\n\nBamboo separates the tasks of email creation and email sending. To use Bamboo,\nyou'll need to define one or more email modules (email creation), define a\nmailer module (email sending), and provide some configuration.\n\nTo create emails, define an email module within your application.\n\n```elixir\n# some/path/within/your/app/email.ex\ndefmodule MyApp.Email do\n  import Bamboo.Email\n\n  def welcome_email do\n    new_email(\n      to: \"john@example.com\",\n      from: \"support@myapp.com\",\n      subject: \"Welcome to the app.\",\n      html_body: \"\u003cstrong\u003eThanks for joining!\u003c/strong\u003e\",\n      text_body: \"Thanks for joining!\"\n    )\n  end\nend\n```\n\nIn addition to the keyword syntax above you can also [compose emails using pipes].\n\nTo send emails, define a mailer module for your application that `use`s\nBamboo's mailer.\n\n```elixir\n# some/path/within/your/app/mailer.ex\ndefmodule MyApp.Mailer do\n  use Bamboo.Mailer, otp_app: :my_app\nend\n```\n\nYour configuration will need to know your OTP application, your mailer module,\nthe adapter you are using, and any additional configuration required by the\nadapter itself.\n\n```elixir\n# config/config.exs\nconfig :my_app, MyApp.Mailer,\n  adapter: Bamboo.MandrillAdapter,\n  api_key: \"my_api_key\"\n```\n\nBamboo uses [Hackney](https://github.com/benoitc/hackney) for making requests.\nIf you want to pass options to Hackney directly, such as controlling\ntimeouts, you can use the `hackney_opts` key:\n\n```elixir\n# config/config.exs\nconfig :my_app, MyApp.Mailer,\n  adapter: Bamboo.MandrillAdapter,\n  api_key: \"my_api_key\",\n  hackney_opts: [\n    recv_timeout: :timer.minutes(1),\n    connect_timeout: :timer.minutes(1)\n  ]\n```\n\n_Other adapter-specific configuration may be required. Be sure to check the\nadapter's docs._\n\nNow that you have configured Bamboo and defined your modules, you can deliver\nemail in fitting places within your application.\n\n```elixir\ndefmodule MyApp.SomeControllerPerhaps do\n  def send_welcome_email do\n    Email.welcome_email()   # Create your email\n    |\u003e Mailer.deliver_now!() # Send your email\n  end\nend\n```\n\nYour application is now set up to send email with Bamboo! :tada:\n\n## Using Adapters\n\nAn adapter is a set of instructions for how to communicate with a specific\nemail delivery service. Bamboo ships with support for [several popular\nservices][available-adapters], there are others made available by the\ncommunity, or you can use other services by writing a custom adapter.\n\nTo use an adapter, declare it in the configuration for your mailer:\n\n```elixir\n# config/config.exs\nconfig :my_app, MyApp.Mailer,\n  adapter: Bamboo.MandrillAdapter\n```\n\nBamboo provides adapters for use in development and testing. To use these\nadapters, declare them in the environment configuration.\n\nThe local adapter [stores emails in memory that can be viewed during\ndevelopment](#viewing-sent-emails). Declare its use in your dev environment.\n\n```elixir\n# config/dev.exs\nconfig :my_app, MyApp.Mailer,\n  adapter: Bamboo.LocalAdapter\n```\n\nThe test adapter sends emails to your running process allowing you to test mail\ndelivery without emails being sent externally. Declare its use in your test\nenvironment.\n\n```elixir\n# config/test.exs\nconfig :my_app, MyApp.Mailer,\n  adapter: Bamboo.TestAdapter\n```\n\nYou can create new adapters for any environment by implementing the\n[`Bamboo.Adapter`] behaviour.\n\n## Delivering Emails in the Background\n\nOften times you don't want to send an email right away because it can block\nprocess completion (e.g. a web request in Phoenix). Bamboo provides a\n`deliver_later` function on your mailers to send emails in the background. It\nalso provides a [`Bamboo.DeliverLaterStrategy`] behaviour that you can\nimplement to tailor your background email sending.\n\nBy default, `deliver_later` uses [`Bamboo.TaskSupervisorStrategy`]. This\nstrategy sends the email right away, but it does so in the background without\nlinking to the calling process, so errors in the mailer won't bring down your\napp.\n\nYou can also create custom strategies by implementing the\n[`Bamboo.DeliverLaterStrategy`] behaviour. For example, you could create\nstrategies for adding emails to a background processing queue such as [exq] or\n[toniq].\n\n## Composing with Pipes\n\nIn addition to creating emails with keyword lists you, can use pipe syntax to\ncompose emails. This is particularly useful for providing defaults (e.g. from\naddress, default layout, etc.)\n\n```elixir\ndefmodule MyApp.Email do\n  import Bamboo.Email\n  import Bamboo.Phoenix\n\n  def welcome_email do\n    base_email() # Build your default email then customize for welcome\n    |\u003e to(\"foo@bar.com\")\n    |\u003e subject(\"Welcome!!!\")\n    |\u003e put_header(\"Reply-To\", \"someone@example.com\")\n    |\u003e html_body(\"\u003cstrong\u003eWelcome\u003c/strong\u003e\")\n    |\u003e text_body(\"Welcome\")\n  end\n\n  defp base_email do\n    new_email()\n    |\u003e from(\"myapp@example.com\") # Set a default from\n    |\u003e put_html_layout({MyApp.LayoutView, \"email.html\"}) # Set default layout\n    |\u003e put_text_layout({MyApp.LayoutView, \"email.text\"}) # Set default text layout\n  end\nend\n```\n\n## Handling Recipients\n\nThe from, to, cc, and bcc addresses can be a string or a 2 element tuple. What\nhappens if you try to send to a list of `MyApp.User`s? Transforming your data\nstructure each time you send an email would be a pain.\n\n```elixir\n# This stinks. Do you want to do this every time you create a new email?\nusers = for user \u003c- users do\n  {user.name, user.email}\nend\n\nnew_email(to: users)\n```\n\nBamboo alleviates this pain by providing the [`Bamboo.Formatter`] protocol. By\nimplementing the protocol for your data structure once, you can pass that\nstruct directly to Bamboo anywhere it expects an address. See the\n[`Bamboo.Email`] and [`Bamboo.Formatter`] docs for more information and\nexamples.\n\n## Interceptors\n\nIt's possible to configure per Mailer interceptors. Interceptors allow you to\nmodify or block emails on the fly.\n\n```elixir\n# config/config.exs\nconfig :my_app, MyApp.Mailer,\n  adapter: Bamboo.MandrillAdapter,\n  interceptors: [MyApp.DenyListInterceptor]\nend\n```\n\nAn interceptor must implement the `Bamboo.Interceptor` behaviour. To prevent\nemail being sent, you can block it with `Bamboo.Email.block/1`.\n\n```elixir\n# some/path/within/your/app/deny_list_interceptor.ex\ndefmodule MyApp.DenyListInterceptor do\n  @behaviour Bamboo.Interceptor\n  @deny_list [\"bar@foo.com\"]\n\n  def call(email) do\n    if email.to in @deny_list do\n      Bamboo.Email.block(email)\n    else\n      email\n    end\n  end\nend\n```\n\n## Using Phoenix Views and Layouts\n\nPhoenix is not required to use Bamboo. But if you want to use Phoenix's views\nand layouts to render emails, see [`bamboo_phoenix`] and [`Bamboo.Phoenix`].\n\n[`bamboo_phoenix`]: https://github.com/thoughtbot/bamboo_phoenix\n[`Bamboo.Phoenix`]: https://hexdocs.pm/bamboo_phoenix/Bamboo.Phoenix.html\n\n## Viewing Sent Emails\n\nBamboo comes with a handy plug for viewing emails sent in development. Now you\ndon't have to look at the logs to get password resets, confirmation links, etc.\nJust open up the sent email viewer and click the link.\n\nSee [`Bamboo.SentEmailViewerPlug`].\n\nHere is what it looks like:\n\n![Screenshot of BambooSentEmailViewer](https://cloud.githubusercontent.com/assets/22394/14929083/bda60b76-0e29-11e6-9e11-5ec60069e825.png)\n\n## Mandrill Specific Functionality (tags, merge vars, templates, etc.)\n\nMandrill offers extra features on top of regular SMTP email like tagging, merge\nvars, templates, and scheduling emails to send in the future. See\n[`Bamboo.MandrillHelper`].\n\n## SendGrid Specific Functionality (templates, substitution tags, scheduled delivery, etc.)\n\nSendGrid offers extra features on top of regular SMTP email like transactional\ntemplates with substitution tags. See [`Bamboo.SendGridHelper`].\n\n## JSON support\n\nBamboo comes with JSON support out of the box via the [Jason] library. To use\nit, add `:jason` to your dependencies:\n\n```elixir\n{:jason, \"~\u003e 1.0\"}\n```\n\nYou can customize it to use another library via the `:json_library`\nconfiguration:\n\n```elixir\nconfig :bamboo, :json_library, SomeOtherLib\n```\n\n## Testing\n\nBamboo separates email creation and email sending. Test email creation by\nasserting against the email struct created by your functions. For example,\nassuming your welcome email accepts a user recipient, provides the correct from\naddress, and provides specific text, you might test like this:\n\n```elixir\ndefmodule MyApp.EmailTest do\n  use ExUnit.Case\n\n  test \"welcome email\" do\n    user = {\"Ralph\", \"ralph@example.com\"}\n\n    email = MyApp.Email.welcome_email(user)\n\n    assert email.to == user\n    assert email.from == \"welcome@myapp.com\"\n    assert email.html_body =~ \"\u003cp\u003eThanks for joining\u003c/p\u003e\"\n    assert email.text_body =~ \"Thanks for joining\"\n  end\nend\n```\n\nTest email sending in integration tests by using the [`Bamboo.TestAdapter`]\nalong with [`Bamboo.Test`]. For example, assuming during the registration\nprocess of your app an email is sent to the user welcoming them to the\napplication, you might test this feature like this:\n\n```elixir\ndefmodule MyApp.RegistrationTest do\n  use ExUnit.Case\n  use Bamboo.Test\n\n  # Remember to use the `Bamboo.TestAdapter` in your test config\n\n  test \"after registering, the user gets a welcome email\" do\n    user = new_user()\n    expected_email = MyApp.Email.welcome_email(user.email)\n\n    MyApp.Registration.create(user)\n\n    assert_delivered_email expected_email\n  end\n\n  defp new_user do\n    # Build a user appropriate to your application\n  end\nend\n```\n\nSee the documentation for [`Bamboo.Test`] for more examples and additional\nhelper functions.\n\n## Available Adapters\n\nHere is a list of adapters that either ship with Bamboo or have been made\navailable by the community. Feel free to open an issue or a PR if you'd like to\nadd a new adapter to the list.\n\n- `Bamboo.LocalAdapter` - Ships with Bamboo. Stores email in memory. Great for local development.\n- `Bamboo.MailgunAdapter` - Ships with Bamboo. Thanks to [@princemaple].\n- `Bamboo.MandrillAdapter` - Ships with Bamboo.\n- `Bamboo.SendGridAdapter` - Ships with Bamboo.\n- `Bamboo.TestAdapter` - Ships with Bamboo. Use in your test environment.\n- `Bamboo.CampaignMonitorAdapter` - See [jackmarchant/bamboo_campaign_monitor](https://github.com/jackmarchant/bamboo_campaign_monitor).\n- `Bamboo.ConfigAdapter` - See [BinaryNoggin/bamboo_config_adapter](https://github.com/BinaryNoggin/bamboo_config_adapter) declare config at runtime.\n- `Bamboo.FallbackAdapter` - See [prosapient/bamboo_fallback](https://github.com/prosapient/bamboo_fallback). Allows using multiple adapters.\n- `Bamboo.GmailAdapter` - See [parkerduckworth/bamboo_gmail](https://github.com/parkerduckworth/bamboo_gmail).\n- `Bamboo.MailjetAdapter` - See [moxide/bamboo_mailjet](https://github.com/moxide/bamboo_mailjet).\n- `Bamboo.PostmarkAdapter` - See [pablo-co/bamboo_postmark](https://github.com/pablo-co/bamboo_postmark).\n- `Bamboo.SendcloudAdapter` - See [linjunpop/bamboo_sendcloud](https://github.com/linjunpop/bamboo_sendcloud).\n- `Bamboo.SesAdapter` - See [kalys/bamboo_ses](https://github.com/kalys/bamboo_ses).\n- `Bamboo.SMTPAdapter` - See [fewlinesco/bamboo_smtp](https://github.com/fewlinesco/bamboo_smtp).\n- `Bamboo.SparkPostAdapter` - See [andrewtimberlake/bamboo_sparkpost](https://github.com/andrewtimberlake/bamboo_sparkpost).\n- `Bamboo.MailtrapSendingAdapter`, `Bamboo.MailtrapSandboxAdapter` - See [railsware/mailtrap-elixir](https://github.com/railsware/mailtrap-elixir)\n\n## Contributing\n\nBefore opening a pull request, please open an issue first.\n\nOnce we've decided how to move forward with a pull request:\n\n    $ git clone https://github.com/beam-community/bamboo.git\n    $ cd bamboo\n    $ mix deps.get\n    $ mix test\n    $ mix format\n\nOnce you've made your additions and `mix test` passes, go ahead and open a PR!\n\nWe run the test suite as well as formatter checks on CI. Make sure you are using\nthe Elixir version defined in the `.tool-versions` file to have consistent\nformatting with what's being run on CI.\n\n\u003c!-- Links --\u003e\n\n[@princemaple]: https://github.com/princemaple\n[`bamboo.adapter`]: https://hexdocs.pm/bamboo/Bamboo.Adapter.html\n[`bamboo.deliverlaterstrategy`]: https://hexdocs.pm/bamboo/Bamboo.DeliverLaterStrategy.html\n[`bamboo.email`]: https://hexdocs.pm/bamboo/Bamboo.Email.html\n[`bamboo.formatter`]: https://hexdocs.pm/bamboo/Bamboo.Formatter.html\n[`bamboo.mandrillhelper`]: https://hexdocs.pm/bamboo/Bamboo.MandrillHelper.html\n[`bamboo.phoenix`]: https://hexdocs.pm/bamboo/Bamboo.Phoenix.html\n[`bamboo.sendgridhelper`]: https://hexdocs.pm/bamboo/Bamboo.SendGridHelper.html\n[`bamboo.sentemailviewerplug`]: https://hexdocs.pm/bamboo/Bamboo.SentEmailViewerPlug.html\n[`bamboo.tasksupervisorstrategy`]: https://hexdocs.pm/bamboo/Bamboo.TaskSupervisorStrategy.html\n[`bamboo.test`]: https://hexdocs.pm/bamboo/Bamboo.Test.html\n[`bamboo.testadapter`]: https://hexdocs.pm/bamboo/Bamboo.TestAdapter.html\n[`bamboo`]: http://github.com/beam-community/bamboo\n[available-adapters]: #available-adapters\n[compose emails using pipes]: #composing-with-pipes\n[create your own adapter]: https://hexdocs.pm/bamboo/Bamboo.Adapter.html\n[docs]: https://hexdocs.pm/bamboo/readme.html\n[exq]: https://github.com/akira/exq\n[free bamboo screencasts from ElixirCasts]: https://elixircasts.io/sending-email-with-bamboo-part-1\n[jason]: https://github.com/michalmuskala/jason\n[toniq]: https://github.com/joakimk/toniq","funding_links":[],"categories":["Email","\u003ca name=\"Elixir\"\u003e\u003c/a\u003eElixir"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeam-community%2Fbamboo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeam-community%2Fbamboo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeam-community%2Fbamboo/lists"}