rails-ai:mailers
Use when sending emails - ActionMailer with async delivery via SolidQueue, templates, previews, and testing
What this skill does
# Email with ActionMailer Send transactional and notification emails using ActionMailer, integrated with SolidQueue for async delivery. Create HTML and text templates, preview emails in development, and test thoroughly. <when-to-use> - Sending transactional emails (password resets, confirmations, receipts) - Sending notification emails (updates, alerts, digests) - Delivering emails asynchronously via background jobs - Creating email templates with HTML and text versions - Testing email delivery and content </when-to-use> <benefits> - **Async Delivery** - ActionMailer integrates with SolidQueue for non-blocking email sending - **Template Support** - ERB templates for HTML and text email versions - **Preview in Development** - See emails without sending via /rails/mailers - **Testing Support** - Full test suite for delivery and content - **Layouts** - Shared layouts for consistent email branding - **Attachments** - Send files (PDFs, images) with emails </benefits> <verification-checklist> Before completing mailer work: - ✅ Async delivery used (deliver_later, not deliver_now) - ✅ Both HTML and text templates provided - ✅ URL helpers used (not path helpers) - ✅ Email previews created for development - ✅ Mailer tests passing (delivery and content) - ✅ SolidQueue configured for background delivery </verification-checklist> <standards> - ALWAYS deliver emails asynchronously with deliver_later (NOT deliver_now) - Provide both HTML and text email templates - Use *_url helpers (NOT *_path) for links in emails - Set default 'from' address in ApplicationMailer - Create email previews for development (/rails/mailers) - Configure default_url_options for each environment - Use inline CSS for email styling (email clients strip external styles) - Test email delivery and content - Use parameterized mailers (.with()) for cleaner syntax </standards> --- ## ActionMailer Setup <pattern name="actionmailer-basic-setup"> <description>Configure ActionMailer for email delivery</description> **Mailer Class:** ```ruby # app/mailers/application_mailer.rb class ApplicationMailer < ActionMailer::Base default from: "[email protected]" layout "mailer" end # app/mailers/notification_mailer.rb class NotificationMailer < ApplicationMailer def welcome_email(user) @user = user @login_url = login_url mail(to: user.email, subject: "Welcome to Our App") end def password_reset(user) @user = user @reset_url = password_reset_url(user.reset_token) mail(to: user.email, subject: "Password Reset Instructions") end end ``` **HTML Template:** ```erb <%# app/views/notification_mailer/welcome_email.html.erb %> <h1>Welcome, <%= @user.name %>!</h1> <p>Thanks for signing up. Get started by logging in:</p> <%= link_to "Login Now", @login_url, class: "button" %> ``` **Text Template:** ```erb <%# app/views/notification_mailer/welcome_email.text.erb %> Welcome, <%= @user.name %>! Thanks for signing up. Get started by logging in: <%= @login_url %> ``` **Usage (Async with SolidQueue):** ```ruby # In controller or service NotificationMailer.welcome_email(@user).deliver_later NotificationMailer.password_reset(@user).deliver_later(queue: :mailers) ``` **Why:** ActionMailer integrates seamlessly with SolidQueue for async delivery. Always use deliver_later to avoid blocking requests. Provide both HTML and text versions for compatibility. </pattern> <antipattern> <description>Using deliver_now in production (blocks HTTP request)</description> <bad-example> ```ruby # ❌ WRONG - Blocks HTTP request thread def create @user = User.create!(user_params) NotificationMailer.welcome_email(@user).deliver_now # Blocks! redirect_to @user end ``` </bad-example> <good-example> ```ruby # ✅ CORRECT - Async delivery via SolidQueue def create @user = User.create!(user_params) NotificationMailer.welcome_email(@user).deliver_later # Non-blocking redirect_to @user end ``` </good-example> **Why bad:** deliver_now blocks the HTTP request until SMTP completes, creating slow response times and poor user experience. deliver_later uses SolidQueue to send email in background. </antipattern> <pattern name="parameterized-mailers"> <description>Use .with() to pass parameters cleanly to mailers</description> ```ruby class NotificationMailer < ApplicationMailer def custom_notification @user = params[:user] @message = params[:message] mail(to: @user.email, subject: params[:subject]) end end # Usage NotificationMailer.with( user: user, message: "Update available", subject: "System Alert" ).custom_notification.deliver_later ``` **Why:** Cleaner syntax, easier to read and modify, and works seamlessly with background jobs. </pattern> --- ## Email Templates <pattern name="email-layouts"> <description>Shared layouts for consistent email branding</description> **HTML Layout:** ```erb <%# app/views/layouts/mailer.html.erb %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; color: #333; } .header { background-color: #4F46E5; color: white; padding: 20px; text-align: center; } .content { padding: 20px; } .button { display: inline-block; padding: 12px 24px; background-color: #4F46E5; color: white; text-decoration: none; border-radius: 4px; } .footer { padding: 20px; text-align: center; font-size: 12px; color: #666; } </style> </head> <body> <div class="header"> <h1>Your App</h1> </div> <div class="content"> <%= yield %> </div> <div class="footer"> <p>© 2025 Your Company. All rights reserved.</p> </div> </body> </html> ``` **Text Layout:** ```erb <%# app/views/layouts/mailer.text.erb %> ================================================================================ YOUR APP ================================================================================ <%= yield %> -------------------------------------------------------------------------------- © 2025 Your Company. All rights reserved. ``` **Why:** Consistent branding across all emails. Inline CSS ensures styling works across email clients. </pattern> <pattern name="email-attachments"> <description>Attach files to emails (PDFs, CSVs, images)</description> ```ruby class ReportMailer < ApplicationMailer def monthly_report(user, data) @user = user # Regular attachment attachments["report.pdf"] = { mime_type: "application/pdf", content: generate_pdf(data) } # Inline attachment (for embedding in email body) attachments.inline["logo.png"] = File.read( Rails.root.join("app/assets/images/logo.png") ) mail(to: user.email, subject: "Monthly Report") end end ``` **In template:** ```erb <%# Reference inline attachment %> <%= image_tag attachments["logo.png"].url %> ``` **Why:** Attach reports, exports, or inline images. Inline attachments can be referenced in email body with image_tag. </pattern> <antipattern> <description>Using *_path helpers instead of *_url in emails (broken links)</description> <bad-example> ```ruby # ❌ WRONG - Relative path doesn't work in emails def welcome_email(user) @user = user @login_url = login_path # => "/login" (relative path) mail(to: user.email, subject: "Welcome") end ``` </bad-example> <good-example> ```ruby # ✅ CORRECT - Full URL works in emails def welcome_email(user) @user = user @login_url = login_url # => "https://example.com/login" (absolute URL) mail(to: user.email, subject: "Welcome") end # Required configuration # config/environments/production.rb config.action_mailer.default_url_options = { host: "example.com", protocol: "https" } ``` </good-example> **Why bad:** Emails are viewed outside your application context, so relative
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.