Docs · Working with Claude Code

The add-mailer and add-job Skills

Walkthrough of adding a transactional email and a background job.

Two small skills, add-mailer and add-job, cover the two most common kinds of work that happen outside the request cycle: sending an email, and doing anything else in the background. Both build on plumbing that's already fully configured, so each skill is short. The concept pages are Sending Email and Background Jobs; this page is the two skills' step-by-step.

add-mailer

Email is already wired end to end: Resend in production, letter_opener in development, :test in specs. Copy app/mailers/sign_in_code_mailer.rb and its views as the template.

  1. Add a method to an existing mailer, or create app/mailers/<name>_mailer.rb subclassing ApplicationMailer. Keep the default from address unless you have a specific reason to override it per message.
  2. Create both app/views/<name>_mailer/<method>.html.erb and the matching .text.erb, for deliverability.
  3. Send it with <Name>Mailer.<method>(...).deliver_later, which delivers asynchronously through Solid Queue. For a delayed send, deliver_later(wait: 5.minutes). See User#send_welcome_email_later for the dev/test inline-fallback pattern this kit uses.
  4. Write spec/mailers/<name>_mailer_spec.rb, asserting recipient, subject, and body, plus a have_enqueued_mail assertion at the trigger site.
  5. Optionally add a spec/mailers/previews/ preview for viewing the rendered email in letter_opener.
  6. Run bin/check.

add-job

Jobs run on Solid Queue, already configured, with no Redis: in-Puma in production, async or inline in development and test.

  1. bin/rails g job <Name> generates app/jobs/<name>_job.rb. Keep perform small and idempotent, since a job may be retried, and operate through account-scoped associations, never a global scope.
  2. Enqueue with <Name>Job.perform_later(record_id), passing ids rather than objects. For future work, set(wait: ...).perform_later.
  3. For periodic work, add an entry to config/recurring.yml, cron-style.
  4. Write spec/jobs/<name>_job_spec.rb, asserting behavior with the job performed inline, and use have_enqueued_job wherever it's triggered.
  5. Run bin/check.

Next

See how to publish content, using the same file-based, no-database pattern the docs site itself is built on: The write-post Skill.