Documentation

Mailers

Updated
Browse documentation

Published 2026-08-13. V2 is a prerelease; the web core is release-gated and other previews are named separately. What beta means.

Read this page as HTML, Markdown, or structured JSON—or open the published Markdown with an AI assistant. Gemini receives the prompt through your clipboard because its signed-out page does not reliably prefill URL text; paste when the new tab opens. External assistants need the public site URL.

Mailers

Amber V2 includes Amber::Mailer::Base, MIME generation, attachments, an in-memory delivery adapter, and SMTP delivery. Generate an ECR-backed mailer with the standalone CLI.

Run from: the application root.

Terminal
amber generate mailer Digest --actions=weekly

The generator writes src/mailers/digest_mailer.cr, an ECR template under src/views/digest_mailer/, and a mailer spec. The generated class implements the required HTML and text bodies.

File: src/mailers/digest_mailer.cr — edit the generated class in place.

Crystal
class DigestMailer < Amber::Mailer::Base
  def initialize(@user_name : String, @user_email : String)
  end

  def html_body : String?
    ECR.render("src/views/digest_mailer/weekly.ecr")
  end

  def text_body : String?
    "Hello, #{@user_name}!"
  end
end

File: src/views/digest_mailer/weekly.ecr — edit the generated HTML body and escape user-provided values.

Crystal
<h1>Hello, <%= HTML.escape(@user_name) %>!</h1>

Delivery configuration

The memory adapter is the default and is appropriate for tests. Configure SMTP at application startup before delivering production mail.

File: config/application.cr — append this configuration after require "amber".

Crystal
Amber::Mailer::Configuration.configure do |config|
  config.adapter = :smtp
  config.smtp_host = ENV["SMTP_HOST"]
  config.smtp_port = ENV.fetch("SMTP_PORT", "587").to_i
  config.smtp_username = ENV["SMTP_USERNAME"]?
  config.smtp_password = ENV["SMTP_PASSWORD"]?
  config.use_tls = true
  config.default_from = ENV.fetch("MAIL_FROM", "[email protected]")
  config.helo_domain = ENV.fetch("SMTP_HELO_DOMAIN", "localhost")
end

Do not commit SMTP credentials.

Build and deliver

File: the controller action or job that owns delivery, for example src/jobs/digest_delivery_job.cr — build the message before calling .deliver.

Crystal
result = DigestMailer.new("Alice", "[email protected]")
  .to("[email protected]")
  .subject("Your weekly digest")
  .deliver

raise result.error.to_s unless result.is_successful

Use .from, .cc, .bcc, .reply_to, .header, .attach, or .attach_file before .deliver when the message needs them. The Quartz-Mailer and Slang examples on the V1 page do not describe Amber V2's mailer API.