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.
/plugin marketplace add bastos/rails-plugin/plugin install bastos-ruby-on-rails@bastos/rails-pluginThis skill inherits all available tools. When active, it can use any tool Claude has access to.
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
require "rails_helper"
RSpec.describe UserMailer, type: :mailer do
describe "#welcome" do
let(:user) { create(:user) }
let(:mail) { described_class.welcome(user) }
it "renders the headers" do
expect(mail.subject).to eq("Welcome to Our App!")
expect(mail.to).to eq([user.email])
expect(mail.from).to eq(["noreply@example.com"])
end
it "renders the body" do
expect(mail.body.encoded).to include(user.name)
end
it "is enqueued" do
expect {
described_class.welcome(user).deliver_later
}.to have_enqueued_mail(UserMailer, :welcome)
end
end
end
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.