{"id":13507848,"url":"https://github.com/jfrolich/smoothie","last_synced_at":"2025-06-19T03:43:33.363Z","repository":{"id":57549666,"uuid":"69011424","full_name":"jfrolich/smoothie","owner":"jfrolich","description":"Beautiful emails for your elixir application","archived":false,"fork":false,"pushed_at":"2017-05-24T06:58:47.000Z","size":69,"stargazers_count":46,"open_issues_count":8,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-07T23:42:34.870Z","etag":null,"topics":["css","elixir","elixir-lang","email","smoothie","stylesheets"],"latest_commit_sha":null,"homepage":"","language":"HTML","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/jfrolich.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-23T09:41:29.000Z","updated_at":"2024-05-13T07:03:58.000Z","dependencies_parsed_at":"2022-09-01T07:11:22.645Z","dependency_job_id":null,"html_url":"https://github.com/jfrolich/smoothie","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrolich%2Fsmoothie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrolich%2Fsmoothie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrolich%2Fsmoothie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrolich%2Fsmoothie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jfrolich","download_url":"https://codeload.github.com/jfrolich/smoothie/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243826783,"owners_count":20354220,"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":["css","elixir","elixir-lang","email","smoothie","stylesheets"],"created_at":"2024-08-01T02:00:40.917Z","updated_at":"2025-03-16T18:31:41.056Z","avatar_url":"https://github.com/jfrolich.png","language":"HTML","funding_links":[],"categories":["Email"],"sub_categories":[],"readme":"# Smoothie\n\nStylesheet inlining and plain text template generation for your email templates.\n\nFollow the installation instructions to set up Smoothie. After that we can use it in the following way in our project:\n\nLet's suppose we are using the excellent Mailgun library to send our emails.\nThen we set up a Mailer module in the following location: `web/mailers/mailer.ex`, with the following content:\n\n```elixir\ndefmodule MyApp.Mailer do\n  # your mailgun config here\n  @config %{...}\n  use Mailgun.Client, @config\n\n  def welcome_email(user) do\n    send_email to: user.email_address,\n               from: \"support@acme.com\",\n               subject: \"Welcome!\",\n               text: \"Welcome #{user.name}\"\n    :ok\n  end\nend\n```\n\nPretty boring right. So lets add smoothie. First we need a layout, lets try this one (save as: `web/mailers/templates/layouts/main.html.eex`):\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"utf-8\"\u003e\n  \u003cmeta name=\"viewport\" content=\"width=device-width\"\u003e\n  \u003cstyle type=\"text/css\"\u003e\n    @media screen and (min-width: 581px) {\n      .container {\n        width: 580px !important;\n      }\n    }\n  \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003ctable class=\"body-wrap\"\u003e\n    \u003ctr\u003e\n      \u003ctd class=\"container\"\u003e\n        \u003ctable\u003e\n          \u003ctr\u003e\n            \u003ctd align=\"center\" class=\"masthead\"\u003e\n              \u003ch1\u003e\u003c%= @title %\u003e\u003c/h1\u003e\n            \u003c/td\u003e\n          \u003c/tr\u003e\n          \u003ctr\u003e\n            \u003ctd class=\"content\"\u003e\n              {content}\n            \u003c/td\u003e\n          \u003c/tr\u003e\n        \u003c/table\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd class=\"container\"\u003e\n        \u003ctable\u003e\n          \u003ctr\u003e\n            \u003ctd class=\"content footer\" align=\"center\"\u003e\n              \u003cp\u003eSent by \u003ca href=\"http://www.acme.com\"\u003eAcme\u003c/a\u003e\u003c/p\u003e\n              \u003cp\u003e\u003ca href=\"mailto:hello@acme.com\"\u003ehello@acme.com\u003c/a\u003e\u003c/p\u003e\n            \u003c/td\u003e\n          \u003c/tr\u003e\n        \u003c/table\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/table\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nAlso, lets add a stylesheet. We can use sass for this! save in `web/mailers/templates/layout/style.scss`. If you just want to use css you can save it as `style.css`.\n\n```scss\n$action-color: #50E3C2;\n\n@media only screen and (min-device-width: 581px) {\n  .container {\n    width: 580px !important;\n  }\n}\n\n\n// Global\n* {\n  margin: 0;\n  padding: 0;\n  font-size: 100%;\n  font-family: 'Avenir Next', \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;\n  line-height: 1.65;\n}\n\nimg {\n  max-width: 100%;\n  margin: 0 auto;\n  display: block;\n}\n\nbody,\n.body-wrap {\n  width: 100% !important;\n  height: 100%;\n  background: #efefef;\n  -webkit-font-smoothing:antialiased;\n  -webkit-text-size-adjust:none;\n}\n\na {\n  color: $action-color;\n  text-decoration: none;\n}\n\n.text-center {\n  text-align: center;\n}\n\n.text-right {\n  text-align: right;\n}\n\n.text-left {\n  text-align: left;\n}\n\n// Button\n.button {\n  display: inline-block;\n  color: white;\n  background: $action-color;\n  border: solid $action-color;\n  border-width: 10px 20px 8px;\n  font-weight: bold;\n  border-radius: 4px;\n}\n\n// Typography\nh1, h2, h3, h4, h5, h6 {\n  margin-bottom: 20px;\n  line-height: 1.25;\n}\nh1 {\n  font-size: 32px;\n}\nh2 {\n  font-size: 28px;\n}\nh3 {\n  font-size: 24px;\n}\nh4 {\n  font-size: 20px;\n}\nh5 {\n  font-size: 16px;\n}\n\np, ul, ol {\n  font-size: 16px;\n  font-weight: normal;\n  margin-bottom: 20px;\n}\n\n// layout\n.container {\n  display: block !important;\n  clear: both !important;\n  margin: 0 auto !important;\n  max-width: 580px !important;\n\n  table {\n    width: 100% !important;\n    border-collapse: collapse;\n  }\n\n  .masthead {\n    padding: 80px 0;\n    background: #50E3C2;\n    color: white;\n\n    h1 {\n      margin: 0 auto !important;\n      max-width: 90%;\n      text-transform: uppercase;\n    }\n  }\n\n  .content {\n    background: white;\n    padding: 30px 35px;\n\n    \u0026.footer {\n      background: none;\n\n      p {\n        margin-bottom: 0;\n        color: #888;\n        text-align: center;\n        font-size: 14px;\n      }\n\n      a {\n        color: #888;\n        text-decoration: none;\n        font-weight: bold;\n      }\n    }\n  }\n}\n```\n\nNow create the template for our email, we can save this in `web/mailers/templates/welcome.html.eex`\n\nOptionally adding additional css styling specific for this template partial is possible using `\u003cstyle\u003e \u003c/style\u003e` tags.\n\n```html\n\u003cstyle\u003e\n    .inner-template{\n        font-size: 120%;\n        color: lightgreen;\n    }\n\u003c/style\u003e\n\n\u003ch2\u003eHi \u003c%= @name %\u003e,\u003c/h2\u003e\n\n\u003cp class=\"inner-template\"\u003eWelcome!\u003c/p\u003e\n\n\u003cp\u003eCheers,\u003c/p\u003e\n\n\u003cp\u003e\u003cem\u003e—The Acme\u003c/em\u003e\u003c/p\u003e\n```\n\nAlright we're all set up, lets make sure this template works in Smoothie:\n\n```elixir\ndefmodule MyApp.Mailer do\n  # your mailgun config here\n  @config %{...}\n  use Mailgun.Client, @config\n  use Smoothie,\n    template_dir: \"templates\",\n    layout_file: Path.join(\"layouts\", \"main.html.eex\")\n\n\n\n  def welcome_email(user) do\n    template_params = [\n      title: \"Big Welcome!\",\n      name: user.name,\n    ]\n\n    send_email to: user.email_address,\n               from: \"support@acme.com\",\n               subject: \"Welcome!\",\n               text: welcome_text(template_params),\n               html: welcome_html(template_params)\n    :ok\n  end\nend\n```\n\nAdditionally to enable smoothie compilation on this module we need to add the module to the configuration (`config/config.exs`):\n\n```elixir\nconfig :smoothie, modules: [MyApp.Mailer]\n```\n\n\nThe last thing to do is to compile the templates, we need to do this every time when we change the templates or the layout:\n\n```\n\u003e mix smoothie.compile\nPreparing to compile the following template files:\n- welcome.html.eex\nCreated welcome.html.eex\nCreated welcome.txt.eex\nDone 🙏\n```\n\nDone! Now we are able to send very beautifully styled templates with styles inlined so it works in every email client, and for we also have a nice plain text version of the email!\n\n## Text templates\n\nSmoothie automatically generates `txt.eex` templates from your `html.eex` files. If you don't like them, you can provide your own `txt.eex` templates by saving them to the same directory as your `html.eex` files.\n\n```\n/build\n/layout\nwelcome.html.eex\nwelcome.txt.eex\n```\n\nTo skip generating text templates altogether, set `:html_only` in your config,\n\n```elixir\nconfig :smoothie, html_only: true\n```\n\nor run `mix smoothie.compile --html-only`.\n\n## Installation\n\nSmoothie can be installed as:\n\n  1. Add `smoothie` to your list of dependencies in `mix.exs`:\n\n  ```elixir\n  def deps do\n    [{:smoothie, \"~\u003e 3.0\"}]\n  end\n  ```\n\n  2. Ensure `smoothie` is started before your application:\n\n  ```elixir\n  def application do\n    [applications: [:smoothie]]\n  end\n  ```\n\n  3. The only thing left is install the npm package that smoothie relies on in your project, we can do this with the following command:\n\n  ```\n    \u003e mix smoothie.init\n  ```\n\n  Compile with layout\n  ```\n    \u003e mix smoothie.compile\n  ```\n\nSmoothie needs to install a npm library to do the css inlining, so make sure you have npm initialized in your project (a `package.json` file in your project's root)\n\n## Tests\n\n```\nyarn install \u0026\u0026 mix test\n```\n\n## TODO\n\n- [ ] Create example usage repository (and link to README)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfrolich%2Fsmoothie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjfrolich%2Fsmoothie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfrolich%2Fsmoothie/lists"}