{"id":13507850,"url":"https://github.com/swoosh/swoosh","last_synced_at":"2026-04-29T04:08:39.740Z","repository":{"id":38454765,"uuid":"53172916","full_name":"swoosh/swoosh","owner":"swoosh","description":"Compose, deliver and test your emails easily in Elixir","archived":false,"fork":false,"pushed_at":"2026-04-28T02:36:22.000Z","size":2260,"stargazers_count":1516,"open_issues_count":13,"forks_count":248,"subscribers_count":12,"default_branch":"main","last_synced_at":"2026-04-28T04:23:00.414Z","etag":null,"topics":["elixir","email"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/swoosh","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/swoosh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-03-04T23:48:56.000Z","updated_at":"2026-04-28T02:33:58.000Z","dependencies_parsed_at":"2026-03-17T19:02:41.884Z","dependency_job_id":null,"html_url":"https://github.com/swoosh/swoosh","commit_stats":{"total_commits":1062,"total_committers":172,"mean_commits":6.174418604651163,"dds":0.6205273069679849,"last_synced_commit":"94dff2196df9a283a3ebf9c314732ea532e947e1"},"previous_names":[],"tags_count":169,"template":false,"template_full_name":null,"purl":"pkg:github/swoosh/swoosh","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swoosh%2Fswoosh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swoosh%2Fswoosh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swoosh%2Fswoosh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swoosh%2Fswoosh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swoosh","download_url":"https://codeload.github.com/swoosh/swoosh/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swoosh%2Fswoosh/sbom","scorecard":{"id":862308,"data":{"date":"2025-08-11","repo":{"name":"github.com/swoosh/swoosh","commit":"ff4ecc6f9bf6b4161f3b0af9d73f6b68d212004b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.3,"checks":[{"name":"Maintained","score":10,"reason":"25 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":5,"reason":"Found 7/14 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/elixir.yml:1","Warn: no topLevel permission defined: .github/workflows/publish-docs.yml:1","Warn: no topLevel permission defined: .github/workflows/publish.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Warn: no topLevel permission defined: .github/workflows/retire.yml:1","Warn: no topLevel permission defined: .github/workflows/spellcheck.yml:1","Warn: no topLevel permission defined: .github/workflows/tailwind.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/elixir.yml:7: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/elixir.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish-docs.yml:7: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/publish-docs.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/publish.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/retire.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/retire.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/spellcheck.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/spellcheck.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tailwind.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/tailwind.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/tailwind.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/tailwind.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tailwind.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/swoosh/swoosh/tailwind.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/spellcheck.yml:14","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   6 third-party GitHubAction dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T01:39:17.808Z","repository_id":38454765,"created_at":"2025-08-24T01:39:17.808Z","updated_at":"2025-08-24T01:39:17.808Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32410019,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T03:46:11.172Z","status":"ssl_error","status_checked_at":"2026-04-29T03:37:55.317Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["elixir","email"],"created_at":"2024-08-01T02:00:40.953Z","updated_at":"2026-04-29T04:08:39.727Z","avatar_url":"https://github.com/swoosh.png","language":"Elixir","funding_links":[],"categories":["Email","Elixir","Code"],"sub_categories":["Library"],"readme":"# Swoosh\n\n[![hex.pm](https://img.shields.io/hexpm/v/swoosh.svg)](https://hex.pm/packages/swoosh)\n[![hex.pm](https://img.shields.io/hexpm/dt/swoosh.svg)](https://hex.pm/packages/swoosh)\n[![hex.pm](https://img.shields.io/hexpm/l/swoosh.svg)](https://hex.pm/packages/swoosh)\n[![github.com](https://img.shields.io/github/last-commit/swoosh/swoosh.svg)](https://github.com/swoosh/swoosh)\n\nCompose, deliver and test your emails easily in Elixir.\n\nSwoosh comes with many adapters, including SendGrid, Mandrill, Mailgun, Postmark and SMTP.\nSee the full list of [adapters below](#adapters).\n\nThe complete documentation for Swoosh is [available online at HexDocs](https://hexdocs.pm/swoosh).\n\n## Requirements\n\nElixir 1.16+ and Erlang OTP 26+\n\n## Getting started\n\n```elixir\n# In your config/config.exs file\nconfig :sample, Sample.Mailer,\n  adapter: Swoosh.Adapters.Sendgrid,\n  api_key: \"SG.x.x\"\n```\n\n```elixir\n# In your application code\ndefmodule Sample.Mailer do\n  use Swoosh.Mailer, otp_app: :sample\nend\n```\n\n```elixir\ndefmodule Sample.UserEmail do\n  import Swoosh.Email\n\n  def welcome(user) do\n    new()\n    |\u003e to({user.name, user.email})\n    |\u003e from({\"Dr B Banner\", \"hulk.smash@example.com\"})\n    |\u003e subject(\"Hello, Avengers!\")\n    |\u003e html_body(\"\u003ch1\u003eHello #{user.name}\u003c/h1\u003e\")\n    |\u003e text_body(\"Hello #{user.name}\\n\")\n  end\nend\n```\n\n```elixir\n# In an IEx session\nemail = Sample.UserEmail.welcome(%{name: \"Tony Stark\", email: \"tony.stark@example.com\"})\nSample.Mailer.deliver(email)\n```\n\n```elixir\n# Or in a Phoenix controller\ndefmodule Sample.UserController do\n  use Phoenix.Controller\n  alias Sample.UserEmail\n  alias Sample.Mailer\n\n  def create(conn, params) do\n    user = create_user!(params)\n\n    UserEmail.welcome(user) |\u003e Mailer.deliver()\n  end\nend\n```\n\nSee [`Swoosh.Mailer`](https://hexdocs.pm/swoosh/Swoosh.Mailer.html) for more\nconfiguration options.\n\n## Installation\n\n- Add swoosh to your list of dependencies in `mix.exs`:\n\n  ```elixir\n  def deps do\n    [{:swoosh, \"~\u003e 1.25\"}]\n  end\n  ```\n\n- (Optional-ish) Most adapters (non SMTP ones) use `Swoosh.ApiClient` to talk\n  to the service provider. Swoosh comes with `Swoosh.ApiClient.Hackney` configured\n  by default. If you want to use it, you just need to include\n  [`Hackney`](https://hex.pm/packages/hackney) as a dependency of your app.\n\n  Swoosh also accepts [`Finch`](https://hex.pm/packages/finch) and [`Req`](https://hex.pm/packages/req) out-of-the-box.\n  See `Swoosh.ApiClient.Finch` and `Swoosh.ApiClient.Req` for details.\n\n  If you need to integrate with another HTTP client, it's easy to define a new\n  API client. Follow the `Swoosh.ApiClient` behaviour and configure Swoosh to\n  use it:\n\n  ```elixir\n  config :swoosh, :api_client, MyApp.ApiClient\n  ```\n\n  But if you don't need `Swoosh.ApiClient`, you can disable it by setting the value\n  to `false`:\n\n  ```elixir\n  config :swoosh, :api_client, false\n  ```\n\n  This is the case when you are using `Swoosh.Adapters.Local`,\n  `Swoosh.Adapters.Test` and adapters that are SMTP based, that don't require\n  an API client.\n\n- (Optional) If you are using `Swoosh.Adapters.SMTP`,\n  `Swoosh.Adapters.Sendmail` or `Swoosh.Adapters.AmazonSES`, you also need to\n  add [`gen_smtp`](https://hex.pm/packages/gen_smtp) to your dependencies:\n\n  ```elixir\n  def deps do\n    [\n      {:swoosh, \"~\u003e 1.6\"},\n      {:gen_smtp, \"~\u003e 1.0\"}\n    ]\n  end\n  ```\n\n## Adapters\n\nSwoosh supports the most popular transactional email providers out of the box\nand also has an SMTP adapter. Below is the list of the adapters currently\nincluded:\n\n| Provider                     | Swoosh adapter                                                                                                                  | Remarks          |\n| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------- |\n| SMTP                         | [Swoosh.Adapters.SMTP](https://hexdocs.pm/swoosh/Swoosh.Adapters.SMTP.html#content)                                             |                  |\n| Mua                          | [Swoosh.Adapters.Mua](https://hexdocs.pm/swoosh/Swoosh.Adapters.Mua.html#content)                                               | SMTP alternative |\n| SendGrid                     | [Swoosh.Adapters.Sendgrid](https://hexdocs.pm/swoosh/Swoosh.Adapters.Sendgrid.html#content)                                     |                  |\n| Brevo                        | [Swoosh.Adapters.Brevo](https://hexdocs.pm/swoosh/Swoosh.Adapters.Brevo.html#content)                                           | Sendinblue       |\n| Sendmail                     | [Swoosh.Adapters.Sendmail](https://hexdocs.pm/swoosh/Swoosh.Adapters.Sendmail.html#content)                                     |                  |\n| Mandrill                     | [Swoosh.Adapters.Mandrill](https://hexdocs.pm/swoosh/Swoosh.Adapters.Mandrill.html#content)                                     |                  |\n| Mailgun                      | [Swoosh.Adapters.Mailgun](https://hexdocs.pm/swoosh/Swoosh.Adapters.Mailgun.html#content)                                       |                  |\n| MailerSend                   | [Swoosh.Adapters.Mailersend](https://hexdocs.pm/swoosh/Swoosh.Adapters.Mailersend.html#content)                                 |                  |\n| Mailjet                      | [Swoosh.Adapters.Mailjet](https://hexdocs.pm/swoosh/Swoosh.Adapters.Mailjet.html#content)                                       |                  |\n| MsGraph                      | [Swoosh.Adapters.MsGraph](https://hexdocs.pm/swoosh/Swoosh.Adapters.MsGraph.html#content)                                       |                  |\n| Postmark                     | [Swoosh.Adapters.Postmark](https://hexdocs.pm/swoosh/Swoosh.Adapters.Postmark.html#content)                                     |                  |\n| SparkPost                    | [Swoosh.Adapters.SparkPost](https://hexdocs.pm/swoosh/Swoosh.Adapters.SparkPost.html#content)                                   |                  |\n| Amazon SES                   | [Swoosh.Adapters.AmazonSES](https://hexdocs.pm/swoosh/Swoosh.Adapters.AmazonSES.html#content)                                   |                  |\n| Amazon SES                   | [Swoosh.Adapters.ExAwsAmazonSES](https://hexdocs.pm/swoosh/Swoosh.Adapters.ExAwsAmazonSES.html)                                 |                  |\n| Customer.io                  | [Swoosh.Adapters.CustomerIO](https://hexdocs.pm/swoosh/Swoosh.Adapters.CustomerIO.html)                                         |                  |\n| Dyn                          | [Swoosh.Adapters.Dyn](https://hexdocs.pm/swoosh/Swoosh.Adapters.Dyn.html#content)                                               |                  |\n| Scaleway                     | [Swoosh.Adapters.Scaleway](https://hexdocs.pm/swoosh/Swoosh.Adapters.Scaleway.html#content)                                     |                  |\n| SocketLabs                   | [Swoosh.Adapters.SocketLabs](https://hexdocs.pm/swoosh/Swoosh.Adapters.SocketLabs.html#content)                                 |                  |\n| Gmail                        | [Swoosh.Adapters.Gmail](https://hexdocs.pm/swoosh/Swoosh.Adapters.Gmail.html#content)                                           |                  |\n| MailPace                     | [Swoosh.Adapters.MailPace](https://hexdocs.pm/swoosh/Swoosh.Adapters.MailPace.html#content)                                     | OhMySMTP         |\n| SMTP2GO                      | [Swoosh.Adapters.SMTP2GO](https://hexdocs.pm/swoosh/Swoosh.Adapters.SMTP2GO.html#content)                                       |                  |\n| ProtonBridge                 | [Swoosh.Adapters.ProtonBridge](https://hexdocs.pm/swoosh/Swoosh.Adapters.ProtonBridge.html#content)                             |                  |\n| Mailtrap                     | [Swoosh.Adapters.Mailtrap](https://hexdocs.pm/swoosh/Swoosh.Adapters.Mailtrap.html#content)                                     |                  |\n| ZeptoMail                    | [Swoosh.Adapters.ZeptoMail](https://hexdocs.pm/swoosh/Swoosh.Adapters.ZeptoMail.html#content)                                   |                  |\n| Postal                       | [Swoosh.Adapters.Postal](https://hexdocs.pm/swoosh/Swoosh.Adapters.Postal.html#content)                                         |                  |\n| Lettermint                   | [Swoosh.Adapters.Lettermint](https://hexdocs.pm/swoosh/Swoosh.Adapters.Lettermint.html#content)                                 |                  |\n| Resend                       | [Swoosh.Adapters.Resend](https://hexdocs.pm/swoosh/Swoosh.Adapters.Resend.html#content)                                         |                  |\n| Azure Communication Services | [Swoosh.Adapters.AzureCommunicationServices](https://hexdocs.pm/swoosh/Swoosh.Adapters.AzureCommunicationServices.html#content) |                  |\n| ------                       | **Below are not fully featured services**                                                                                       | ------           |\n| Loops                        | [Swoosh.Adapters.Loops](https://hexdocs.pm/swoosh/Swoosh.Adapters.Loops.html#content)                                           |                  |\n| PostUp                       | [Swoosh.Adapters.PostUp](https://hexdocs.pm/swoosh/Swoosh.Adapters.PostUp.html#content)                                         |                  |\n\nConfigure which adapter you want to use by updating your `config/config.exs`\nfile:\n\n```elixir\nconfig :sample, Sample.Mailer,\n  adapter: Swoosh.Adapters.SMTP\n  # adapter config (api keys, etc.)\n```\n\nCheck the documentation of the adapter you want to use for more specific\nconfigurations and instructions.\n\nAdding new adapters is super easy and we are definitely looking for\ncontributions on that front. Get in touch if you want to help!\n\nFor local development and tests, these built-in adapters are also worth knowing:\n\n- [`Swoosh.Adapters.Local`](https://hexdocs.pm/swoosh/Swoosh.Adapters.Local.html#content)\n  stores emails locally so you can inspect them or use\n  [`Plug.Swoosh.MailboxPreview`](https://hexdocs.pm/swoosh/Plug.Swoosh.MailboxPreview.html#content).\n- [`Swoosh.Adapters.Test`](https://hexdocs.pm/swoosh/Swoosh.Adapters.Test.html#content)\n  works with [`Swoosh.TestAssertions`](https://hexdocs.pm/swoosh/Swoosh.TestAssertions.html#content)\n  in unit tests and basic integration tests.\n- [`Swoosh.Adapters.Sandbox`](https://hexdocs.pm/swoosh/Swoosh.Adapters.Sandbox.html#content)\n  is the async-safe testing adapter for feature, browser, and E2E tests where\n  email delivery happens in separate processes.\n\n### Third-party Adapters\n\nAdapters for email providers not included by Swoosh, maintained by Elixir community members.\n\n| Provider | Swoosh adapter                                                                | Remarks |\n| -------- | ----------------------------------------------------------------------------- | ------- |\n| Resend   | [Resend.Swoosh.Adapter](https://hexdocs.pm/resend/Resend.Swoosh.Adapter.html) |         |\n\n## Recipient\n\nThe Recipient Protocol enables you to easily make your structs compatible\nwith Swoosh functions.\n\n```elixir\ndefmodule MyUser do\n  @derive {Swoosh.Email.Recipient, name: :name, address: :email}\n  defstruct [:name, :email, :other_props]\nend\n```\n\nNow you can directly pass `%MyUser{}` to `from`, `to`, `cc`, `bcc`, etc.\nSee `Swoosh.Email.Recipient` for more details.\n\n## Async Emails\n\nSwoosh does not make any special arrangements for sending emails in a\nnon-blocking manner. Opposite to some stacks, sending emails, talking\nto third party apps, etc in Elixir do not block or interfere with other\nrequests, so you should resort to async emails only when necessary.\n\nOne simple way to deliver emails asynchronously is by leveraging Elixir's\nstandard library. First add a Task supervisor to your application root,\nusually at `lib/my_app/application.ex`:\n\n```elixir\ndef start(_, _) do\n  children = [\n    ...,\n    # Before the endpoint\n    {Task.Supervisor, name: MyApp.AsyncEmailSupervisor},\n    MyApp.Endpoint\n  ]\n\n  Supervisor.start_link(children, strategy: :one_for_one)\nend\n```\n\nNow, whenever you want to send an email:\n\n```elixir\nTask.Supervisor.start_child(MyApp.AsyncEmailSupervisor, fn -\u003e\n  %{name: \"Tony Stark\", email: \"tony.stark@example.com\"}\n  |\u003e Sample.UserEmail.welcome()\n  |\u003e Sample.Mailer.deliver()\nend)\n```\n\nPlease take a look at the official docs for\n[Task](https://hexdocs.pm/elixir/Task.html) and\n[Task.Supervisor](https://hexdocs.pm/elixir/Task.Supervisor.html) for further\noptions.\n\nOne of the downsides of sending email asynchronously is that failures won't\nbe reported to the user, who won't have an opportunity to try again immediately,\nand tasks by default do not retry on errors. Therefore, if the email must be\ndelivered asynchronously, a safer solution would be to use a queue or job system.\nElixir's ecosystem has many\n[job queue libraries](https://hex.pm/packages?search=job+queue\u0026sort=recent_downloads).\n\n- [Oban](https://hexdocs.pm/oban/Oban.html) is the current community favourite.\n  It uses PostgreSQL for storage and coordination.\n- [Exq](https://hexdocs.pm/exq/readme.html) uses Redis and is compatible with\n  Resque / Sidekiq.\n\n## Attachments\n\nYou can attach files to your email using the `Swoosh.Email.attachment/2`\nfunction. Just give the path of your file as an argument and we will do the\nrest. It also works with a `%Plug.Upload{}` struct, or a `%Swoosh.Attachment{}`\nstruct, which can be constructed using `Swoosh.Attachment.new` detailed here in\nthe [docs](https://hexdocs.pm/swoosh/Swoosh.Attachment.html#new/2).\n\nAll built-in adapters have support for attachments.\n\n```elixir\nnew()\n|\u003e to(\"peter@example.com\")\n|\u003e from({\"Jarvis\", \"jarvis@example.com\"})\n|\u003e subject(\"Invoice May\")\n|\u003e text_body(\"Here is the invoice for your superhero services in May.\")\n|\u003e attachment(\"/Users/jarvis/invoice-peter-may.pdf\")\n```\n\n## Testing\n\nIn your `config/test.exs` file set your mailer's adapter to\n`Swoosh.Adapters.Test` so that you can use the assertions provided by Swoosh in\n`Swoosh.TestAssertions` module.\n\n```elixir\ndefmodule Sample.UserTest do\n  use ExUnit.Case, async: true\n\n  import Swoosh.TestAssertions\n\n  test \"send email on user signup\" do\n    # Assuming `create_user` creates a new user then sends out a\n    # `Sample.UserEmail.welcome` email\n    user = create_user(%{username: \"ironman\", email: \"tony.stark@example.com\"})\n    assert_email_sent Sample.UserEmail.welcome(user)\n  end\nend\n```\n\nFor feature, browser, and E2E tests where email delivery happens outside the\ntest process tree, use\n[`Swoosh.Adapters.Sandbox`](https://hexdocs.pm/swoosh/Swoosh.Adapters.Sandbox.html#content)\ninstead. Its module docs include setup instructions for standard ExUnit tests,\nPhoenix integration, and browser-test helpers.\n\n## Custom JSON Library\n\nBy default, Swoosh ships with required dependency `Jason`. In the future, we will change it to the builtin `JSON` module in Elixir 1.18+.\nIf you want to swap the default JSON library used by Swoosh, you can configure it in your `config/config.exs` file like this:\n\n```elixir\nconfig :swoosh, :json_library, JSON\n```\n\nIn future major versions, `Jason` will be removed from the dependency list or become an optional dependency.\n\n## Mailbox preview in the browser\n\nSwoosh ships with a Plug that allows you to preview the emails in the local\n(in-memory) mailbox. It's particularly convenient in development when you want\nto check what your email will look like while testing the various flows of your\napplication.\n\nFor email to reach this mailbox you will need to set your `Mailer` adapter to\n`Swoosh.Adapters.Local`:\n\n```elixir\n# in config/dev.exs\nconfig :sample, MyApp.Mailer,\n  adapter: Swoosh.Adapters.Local\n```\n\nIn your Phoenix project you can `forward` directly to the plug\nwithout spinning up a separate webserver, like this:\n\n```elixir\n# in web/router.ex\nif Mix.env == :dev do\n  scope \"/dev\" do\n    pipe_through [:browser]\n\n    forward \"/mailbox\", Plug.Swoosh.MailboxPreview\n  end\nend\n```\n\nYou can also start a new server if your application does not depends on Phoenix:\n\n```elixir\n# in config/dev.exs\n# to run the preview server alongside your app\n# which may not have a web interface already\nconfig :swoosh, serve_mailbox: true\n```\n\n```elixir\n# in config/dev.exs\n# to change the preview server port (4000 by default)\nconfig :swoosh, serve_mailbox: true, preview_port: 4001\n```\n\nWhen using `serve_mailbox: true` make sure to have either `plug_cowboy` or\n`bandit` as a dependency of your app.\n\n```elixir\n{:plug_cowboy, \"\u003e= 1.0.0\"}\n# or\n{:bandit, \"\u003e= 1.0.0\"}\n```\n\nAnd finally you can also use the following Mix task to start the mailbox\npreview server independently:\n\n```console\nmix swoosh.mailbox.server\n```\n\n_Note_: the mailbox preview won't display emails\nbeing sent from outside its own node. So if you are testing using an `IEx` session,\nit's recommended to boot the application in the same session.\n`iex -S mix phx.server` or `iex -S mix swoosh.mailbox.server` will do the trick.\n\nIf you are curious, this is how it the mailbox preview looks like:\n\n![Plug.Swoosh.MailboxPreview](https://github.com/swoosh/swoosh/raw/main/images/mailbox-preview.png)\n\n_Note_ : To show the preview we use the cdn-version of Tailwindcss. If you have set a `content-security-policy` you may have to add `https://cdn.tailwindcss.com` to `default-src` to have the correct make up.\n\nThe preview is also available as a JSON endpoint.\n\n```sh\ncurl http://localhost:4000/dev/mailbox/json\n```\n\n### Production\n\nSwoosh starts a memory storage process for local adapter by default. Normally\nit does no harm being left around in production. However, if it is causing\nproblems, or you don't like having it around, it can be disabled like so:\n\n```elixir\n# config/prod.exs\nconfig :swoosh, local: false\n```\n\n## Telemetry\n\nThe following events are emitted:\n\n- `[:swoosh, :deliver, :start]`: occurs when `Mailer.deliver/2` begins.\n- `[:swoosh, :deliver, :stop]`: occurs when `Mailer.deliver/2` completes.\n- `[:swoosh, :deliver, :exception]`: occurs when `Mailer.deliver/2` throws an exception.\n- `[:swoosh, :deliver_many, :start]`: occurs when `Mailer.deliver_many/2` begins.\n- `[:swoosh, :deliver_many, :stop]`: occurs when `Mailer.deliver_many/2` completes.\n- `[:swoosh, :deliver_many, :exception]`: occurs when `Mailer.deliver_many/2`\n  throws an exception.\n\nView [example in docs](https://hexdocs.pm/swoosh/Swoosh.Mailer.html#module-telemetry)\n\n## Documentation\n\nDocumentation is written into the library, you will find it in the source code,\naccessible from `iex` and of course, it all gets published to\n[HexDocs](http://hexdocs.pm/swoosh).\n\n## Contributing\n\nWe are grateful for any contributions. Before you submit an issue or a pull\nrequest, remember to:\n\n- Look at our [Contributing guidelines](CONTRIBUTING.md)\n- Not use the issue tracker for help or support requests (try StackOverflow,\n  IRC or Slack instead)\n- Do a quick search in the issue tracker to make sure the issues hasn't been\n  reported yet.\n- Look and follow the [Code of Conduct](CODE_OF_CONDUCT.md). Be nice and have fun!\n\n### Running tests\n\nClone the repo and fetch its dependencies:\n\n```sh\ngit clone https://github.com/swoosh/swoosh.git\ncd swoosh\nmix deps.get\nmix test\n```\n\n### Building docs\n\n```sh\nMIX_ENV=docs mix docs\n```\n\n## LICENSE\n\nSee [LICENSE](https://github.com/swoosh/swoosh/blob/main/LICENSE.txt)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswoosh%2Fswoosh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswoosh%2Fswoosh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswoosh%2Fswoosh/lists"}