These docs walk you through adding, updating and using the ActionMailer component library in your Ruby on Rails apps.
Each ActionMailer UI component is a ViewComponent under the hood. Make sure
you have the latest version of the ViewComponent gem installed by adding it to your
# Should be included in :development, :test and :production groups bundle add view_component
components.zip file (recommended)
components.zip file is the easiest way to get started with these ActionMailer components. Visit
the components page and click the
[Download .zip] button in the ActionMailer components section (make
you're logged in).
components.zip includes everything you need to get started -
components/, which contains every ActionMailer
templates/, which contains every ActionMailer template. These are great starting points for your mailer templates.
components/ folder from
components.zip into the
app/components directory of your Ruby on Rails app.
Note: If you're already using ViewComponents, you already have an
app/components/folder. In that case, just copy the
This will make the components available in ALL your views (not just your mailer templates). You probably won't
use these outside of your emails though, hence the
Copy individual components (alternative)
If you don't want to download the
components.zip, or if you want to grab the "stock" version of a component (perhaps
went a bit too gung-ho with modifying one 😅), you can do that too.
The source code for each component can be copied directly. Visit the components page and navigate to the components you want to download.
The following components are REQUIRED —
base.rb— all other components inherit from
colors.rb— most components use colors from this module
::Containerwill try to render this module
- One of the
bg) — all other email components must be rendered into a
Copy each of these components into a correctly named file inside the
app/components/email folder of your Ruby on Rails
Note: I highly recommend you just grab the
components.zipfile and copy the components across that way. It's much easier and will save you some headaches.
Build your mailers
Once you've installed the components correctly, they'll be available in your mailer views under the
namespace. For example, the button component is available as
For more information, I recommend you look at the included mailer templates, which will show you how to correctly use these components (plus some more advanced techniques).
Occasionally, the RailsNotes UI ActionMailer component library will be updated. New templates may also be released.
Some updates may include breaking changes to components. I do my best to minimize these (I know that patching components can be a pain!), but they might be needed for bug fixes or major new features. See the changelog for info on the latest updates.
You're never forced to update your components. The code is already in your app! However, keeping your components up to date will give you bug fixes and improvements. New templates will also use the latest versions of components.
If you follow the recommended way to update — overwriting all your components with their new versions — updating should be painless. I strongly recommend you follow the recommended update method.
Overwriting old components (recommended)
The recommended way to update your components, as with installing them, is to download the
components.zip file and replace the entire
app/components/email folder in your app. Just copy
components/email folder from the new
components.zip file into the
app/components folder of your Ruby on
Rails app, and overwrite the old
app/components/email folder in your Ruby on Rails app will overwrite any edits you made to your
component files! (but not your mailer templates).
Updating individual files (alternative)
You can update components manually by copying across their new versions. You might do this if you've directly
edited some components (ie: edited
text.rb), and want to selectively update your components to preserve their edits.
You can do this by visiting each component's page, and copying across the updated code.
In general, I recommend you avoid updating your components manually (file-by-file). It's error-prone and may lead to bugs. It's a lot easier to copy across the new files from
components.zip, and will help preserve your sanity.
Any new templates will also be included in a new version of the
components.zip file. As usual, you can also grab them
from the RailsNotes UI website.
Why make updating so convoluted? Why not release a gem?
I want to give you full control over your email components. Emails are a core part of your app! I want to give you the power to dive deep into your components and see what's going on — packaging them as a gem would hinder this. It would also force you to rely on me to keep the gem server live.
By giving you the code directly, you get full control over your components and aren't forced to rely on me. The tradeoff is that updates become a bit more involved.
In general, I plan to avoid updating old components where I can help it! I get that it's cumbersome to update your components (despite my best efforts to streamline things). For bug fixes though, there's not really another option.
As long as you don't edit component files directly, updating should be pretty painless. Just copy across the new components, overwrite the old ones, and (possibly) tweak your custom mailer templates.
Building your mailer templates
This section is a mini-teardown of a typical email template built with the ActionMailer component library. This will help you build your own mailer templates.
A typical mailer template
Here's a basic mailer template, built with RailsNotes UI components —
<%= render Email::Bg::Container.new do |email| %> <% email.with_masthead_text(text: "RailsNotes UI", href: "https://railsnotesui.xyz") %> <%# Headings and some body text %> <%= render Email::Heading.new(text: "Thanks for joining!", align: "center") %> <%= render Email::Text.new(text: "Thank you for joining my mailing list!") %> <%# Button inside a gray container %> <%= render Email::Colorblock.new(color: Email::Colors::GRAY_50) do %> <%= render Email::Button.new( text: "Buy something now →", href: "https://example.com/checkout" ) %> <% end %> <%# Text with a link. We pass a block to Email::Text, so we can use the link_to helper %> <%= render Email::Text.new do %> If you have any questions, send an email to <%= link_to "[email protected]", "[email protected]" %>. <% end %> <%# The ::Footer is optional, and must be the last component inside the container. %> <%= render Email::Footer.new do %> © RailsNotes 2023 <% end %> <% end %>
What's going on here?
- All mailer templates start with a
::Container. The container wraps all the other parts of our email. In this case, we use the
- We then render an
Email::MastheadTextcomponent by calling
email.with_masthead_text. This is ViewComponent Slot Syntax. A masthead is optional and sits above the main email container.
- We then render some text components by passing a
text:string to them directly.
- Next, we render an
::Coloblockcomponent wraps other email components and renders them inside a colored container. We override the default color with
Email::Colors::GRAY_50, and pass in a block containing a button.
- Next, we render some more text, but this time we pass
::Texta block. This lets us use the
link_tohelper to generate a link.
- Finally, we render a
::Footerat the end of our mailer template. Rendering a footer is optional, but it must go at the end of your mailer template (if you use it).
Override default styles in base.rb
Email::Base component, located in
base.rb, is unique and worth looking at.
This component is where we define default styles for most other components.
For example, we define default styles for the
Email::Text component inside the
TextStyles class -
class Email::Base < ViewComponent::Base # ... class TextStyles SIZE = "16px" COLOR = Email::Colors::GRAY_900 # [dark variant available] end end
Email::Text component (see
text.rb), we inherit the default styles -
class Email::Text < Email::Base def initialize( # ... size: TextStyles::SIZE, color: TextStyles::COLOR, ) @size = size @color = color end end
This gives us a way to override the global styles of individual components. If you want to make your body
text a bit larger, rather than passing
size: "18px" each time you create an
Email::Text component, you can adjust it
base.rb. You would just set
TextStyles.SIZE = '18px'.
I go over this a bit more in the next section, so if you're feeling a bit lost or confused, read on. You can also email me directly at [email protected] if you're having trouble.
Default Values, Dark Mode and the
Most components only have 1-2 required parameters. The other parameters are set by default but can be overridden if you want to customize your components more thoroughly.
For example, look at the
Email::Button component —
# app/components/email/button.rb # # class Email::Button < Email::Base def initialize( text:, href:, color: ButtonStyles::BACKGROUND_COLOR, # inherited from Email::Base text_color: ButtonStyles::TEXT_COLOR, # inherited from Email::Base margin: "30px 0 30px 0", border_radius: "8px" ) ... end ... end
Email::Button component only requires the
href: attributes. Everything else has a default value,
but you can override them!
Overriding default values
Here are some examples of rendering components and overriding their default values (using the
In the first example, we don't pass in any parameters, which raises an
ArgumentError. In the second example, we
only pass the required parameters, and in the third example, we override a default value.
# no params, raises ArgumentError, "missing keyword" # Email::Button.new # required params only # Email::Button.new( text: "Click me", href: "https://example.com" ) # overriding an optional param # Email::Button.new( text: "Click me", href: "https://example.com", color: Email::Colors::GREEN_500 # using the included Colors:: module )
For more examples check out the example templates, or the file-level comments for each component (which include some usage examples).
You can edit the
Email::Base class to customize the default styles of your components. For example, you could change
all your buttons to be green.
Email::Base class (inside
components/email/base.rb) holds default values for all other components. These
values then get inherited by each component.
For example, this is how the default background color of a button is set to
# Email::Base contains the default styles for most components # class Email::Base < ViewComponent::Base ... class ButtonStyles BACKGROUND_COLOR = Email::Colors::RED_500 # [dark variant available] ... end ... end
If you wanted to change the default button color to green, you could do
BACKGROUND_COLOR = Email::Colors::GREEN_500.
Some components support dark variants, however, they can only be customized globally inside
base.rb. This is
we insert dark variants as
@media queries into the
base.rb, the styling for dark variants lives inside the
DarkStyles class —
# Styles for dark mode rendering # NOTE: These styles can _only_ be configured here (due to how we handle media queries). # You can't adjust the dark mode display for individual elements. class DarkStyles # whether dark mode media queries are included in your emails # set this false to disable dark mode # useful if your mailer templates use dark colors even in "light" mode ENABLED = true # Email::Container CONTAINER_COLOR = Email::Colors::GRAY_800 CONTAINER_SURROUNDS_COLOR = Email::Colors::GRAY_900 CONTAINER_TEXT_COLOR = Email::Colors::GRAY_100 # Email::Button BUTTON_COLOR = Email::Colors::GRAY_100 BUTTON_TEXT_COLOR = Email::Colors::GRAY_900 # Email::Colorblock COLORBLOCK_COLOR = Email::Colors::GRAY_900 end
If you want to change how your email looks in dark mode, you need to edit these values.
You can also completely disable dark mode by setting
ENABLED=false. This will remove all the
associated with dark mode from the
::Container components. This can be useful if you're building a template that's
dark by default, and dont want anything to change on a dark color scheme.
I've added a
Colors:: module into the project, to save you looking up
#hex codes all day.
This module is based on the TailwindCSS color palette and uses naming
Email::Colors::RED_500 to correspond to hex strings.
Using this module is optional! But I find it very handy — It's a great way to quickly tweak the colors in your email, and gives you a good starting point.
If you prefer to use
#hex codes though, you can! Anywhere you see a
Colors:: value, you can replace it with a
#hex string. If you peek inside
colors.rb, you'll see that this module just maps names
Email::Colors::RED_500 to their matching hex strings.
Most components have documentation and examples as file-level comments. The example code should be copy-pastable straight into your ERB templates.
Here's the comment at the top of the
Email::Button component -
# Email::Button component [supports dark variant] # REQUIRED: text:, href: # NOTES: # - href: needs to be an absolute url (good="https://example.com", bad="example.com") # # # Example 1 (simple): # <%= render Email::Button.new( # text: "Simple Button", # href: "https://example.com", # ) %> # # Example 2 (override styles): # <%= render Email::Button.new( # text: "Advanced button → ", # href: "https://example.com", # color: Email::Colors::ORANGE_500, # text_color: Email::Colors::ORANGE_50, # text_size: "20px", # width: "48px", # height: "16px", # border_radius: "60px", # margin: "60px auto 0 auto" # ) %>