Help us improve
Share bugs, ideas, or general feedback.
From ruby-on-rails
This skill should be used when the user asks about "email", "mailers", "Action Mailer", "deliver_now", "deliver_later", "email templates", "attachments", "mail previews", "SMTP", "email configuration", "interceptors", or needs guidance on sending emails in Rails applications.
npx claudepluginhub bastos/ruby-plugin-marketplace --plugin ruby-on-railsHow this skill is triggered — by the user, by Claude, or both
Slash command
/ruby-on-rails:action-mailerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Comprehensive guide to sending emails in Rails applications.
Creates or refactors Rails Action Mailer emails using 7.1+ conventions, parameterized mailers, preview workflows, background delivery, I18n, attachments, and RSpec tests.
Implements Rails ActionMailer for async email delivery via SolidQueue, with HTML/text templates, previews, testing, layouts, and attachments. Use for transactional and notification emails.
Integrates email sending into projects with Resend/SendGrid. Covers domain verification (SPF/DKIM/DMARC), HTML templates, rate limiting, testing, and troubleshooting for verification, notifications, or marketing emails.
Share bugs, ideas, or general feedback.
Comprehensive guide to sending emails in Rails applications.
rails generate mailer User welcome reset_password
# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: "noreply@example.com"
layout "mailer"
end
# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
def welcome(user)
@user = user
@login_url = login_url
mail(
to: @user.email,
subject: "Welcome to Our App!"
)
end
def reset_password(user)
@user = user
@reset_url = edit_password_url(token: @user.reset_token)
mail(to: @user.email, subject: "Reset Your Password")
end
end
mail(
to: "user@example.com", # Single recipient
to: ["a@ex.com", "b@ex.com"], # Multiple recipients
from: "sender@example.com",
cc: "manager@example.com",
bcc: "archive@example.com",
reply_to: "support@example.com",
subject: "Email Subject",
content_type: "text/html", # Default is multipart
importance: "high",
delivery_method_options: { ... }
)
class ApplicationMailer < ActionMailer::Base
default from: "noreply@example.com",
reply_to: "support@example.com"
end
class UserMailer < ApplicationMailer
default from: "users@example.com" # Override for this mailer
end
# Passing params
UserMailer.with(user: @user, account: @account).welcome.deliver_later
# Accessing params
class UserMailer < ApplicationMailer
def welcome
@user = params[:user]
@account = params[:account]
mail(to: @user.email)
end
end
app/views/user_mailer/
├── welcome.html.erb # HTML version
├── welcome.text.erb # Plain text version
└── reset_password.html.erb
<%# app/views/user_mailer/welcome.html.erb %>
<h1>Welcome, <%= @user.name %>!</h1>
<p>Thanks for signing up. Get started by visiting your dashboard:</p>
<p><%= link_to "Go to Dashboard", dashboard_url %></p>
<p>
Best regards,<br>
The Team
</p>
<%# app/views/user_mailer/welcome.text.erb %>
Welcome, <%= @user.name %>!
Thanks for signing up. Get started by visiting your dashboard:
<%= dashboard_url %>
Best regards,
The Team
<%# app/views/layouts/mailer.html.erb %>
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<style>
body { font-family: Arial, sans-serif; }
.header { background: #3498db; color: white; padding: 20px; }
.content { padding: 20px; }
.footer { color: #666; font-size: 12px; padding: 20px; }
</style>
</head>
<body>
<div class="header">
<%= image_tag attachments['logo.png'].url if attachments['logo.png'] %>
</div>
<div class="content">
<%= yield %>
</div>
<div class="footer">
<p>© <%= Date.current.year %> Our Company</p>
<p><%= link_to "Unsubscribe", unsubscribe_url %></p>
</div>
</body>
</html>
class ReportMailer < ApplicationMailer
def monthly_report(user, report)
@user = user
# From file
attachments["report.pdf"] = File.read(report.path)
# With options
attachments["data.csv"] = {
mime_type: "text/csv",
content: generate_csv(report)
}
mail(to: @user.email, subject: "Monthly Report")
end
end
def welcome(user)
@user = user
attachments.inline["logo.png"] = File.read("app/assets/images/logo.png")
mail(to: @user.email)
end
<%# In template %>
<%= image_tag attachments['logo.png'].url %>
# Queue for background delivery
UserMailer.welcome(@user).deliver_later
# With delay
UserMailer.welcome(@user).deliver_later(wait: 1.hour)
UserMailer.welcome(@user).deliver_later(wait_until: Date.tomorrow.noon)
# With options
UserMailer.welcome(@user).deliver_later(queue: :mailers, priority: 10)
# Send immediately (blocks)
UserMailer.welcome(@user).deliver_now
# Useful in background jobs
class WelcomeJob < ApplicationJob
def perform(user)
UserMailer.welcome(user).deliver_now
end
end
# test/mailers/previews/user_mailer_preview.rb
class UserMailerPreview < ActionMailer::Preview
def welcome
user = User.first || User.new(name: "Test User", email: "test@example.com")
UserMailer.welcome(user)
end
def reset_password
user = User.first
UserMailer.reset_password(user)
end
end
Access at: http://localhost:3000/rails/mailers/user_mailer/welcome
# config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener # View in browser
# or
config.action_mailer.delivery_method = :test # Store in ActionMailer::Base.deliveries
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_caching = false
# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { host: "example.com" }
config.action_mailer.smtp_settings = {
address: "smtp.example.com",
port: 587,
domain: "example.com",
user_name: Rails.application.credentials.smtp[:user],
password: Rails.application.credentials.smtp[:password],
authentication: "plain",
enable_starttls_auto: true
}
# SendGrid
config.action_mailer.smtp_settings = {
address: "smtp.sendgrid.net",
port: 587,
authentication: :plain,
user_name: "apikey",
password: ENV["SENDGRID_API_KEY"],
domain: "example.com",
enable_starttls_auto: true
}
# Mailgun
config.action_mailer.smtp_settings = {
address: "smtp.mailgun.org",
port: 587,
user_name: ENV["MAILGUN_SMTP_LOGIN"],
password: ENV["MAILGUN_SMTP_PASSWORD"],
authentication: :plain,
enable_starttls_auto: true
}
# app/mailers/sandbox_email_interceptor.rb
class SandboxEmailInterceptor
def self.delivering_email(message)
message.to = ["sandbox@example.com"]
message.subject = "[SANDBOX] #{message.subject}"
end
end
# config/initializers/mail_interceptors.rb
if Rails.env.staging?
ActionMailer::Base.register_interceptor(SandboxEmailInterceptor)
end
# app/mailers/email_delivery_observer.rb
class EmailDeliveryObserver
def self.delivered_email(message)
EmailLog.create!(
to: message.to.join(", "),
subject: message.subject,
sent_at: Time.current
)
end
end
# config/initializers/mail_observers.rb
ActionMailer::Base.register_observer(EmailDeliveryObserver)
require "test_helper"
class UserMailerTest < ActionMailer::TestCase
test "welcome email" do
user = users(:one)
email = UserMailer.welcome(user)
assert_emails 1 do
email.deliver_now
end
assert_equal ["noreply@example.com"], email.from
assert_equal [user.email], email.to
assert_equal "Welcome to Our App!", email.subject
assert_match user.name, email.body.encoded
end
test "welcome email is enqueued" do
user = users(:one)
assert_enqueued_emails 1 do
UserMailer.welcome(user).deliver_later
end
end
end