mailer

Mailer

MVC::Keayl::Mailer builds email the way a controller builds a response: an action renders HAML views into the parts of a message, and a delivery method sends it.

Defining a mailer

Subclass MVC::Keayl::Mailer and give each action a method that calls mail:

class NoticeMailer is MVC::Keayl::Mailer {
  method welcome($user) {
    self.mail(
      to      => $user.email,
      from    => '[email protected]',
      subject => 'Welcome',
      locals  => %( name => $user.name ),
    );
  }
}

build($action, |args) runs the action and returns the MVC::Keayl::Mail; deliver($action, |args) builds it and hands it to the configured delivery, returning the mail.

my $mailer = NoticeMailer.new(view-renderer => $view, delivery => $delivery);
$mailer.deliver('welcome', $user);

Views

mail renders the message body from views named for the mailer and action, <mailer-path>/<action> (so NoticeMailer#welcome looks under notice_mailer/welcome). It renders an html and a text part when both templates exist:

app/views/notice_mailer/welcome.html.haml
app/views/notice_mailer/welcome.text.haml

A message with both parts is multipart; one with a single template carries just that part. Pass :template to override the lookup, :locals for the view locals, :cc / :bcc for extra recipients, :reply-to for a reply address, and :headers for custom headers. default-from on the mailer supplies a sender when an action gives none.

Class-level defaults

default sets values an action falls back to. An explicit value on the action always wins:

class NoticeMailer is MVC::Keayl::Mailer { ... }
NoticeMailer.default(from => '[email protected]', reply-to => '[email protected]');

Keys other than from and reply-to become default headers merged into every message.

Callbacks

before-action and after-action run around the action. Each receives the mailer; the built message is available as self.message after the action runs:

NoticeMailer.before-action(-> $mailer { ... });
NoticeMailer.after-action(-> $mailer { $mailer.message.headers<X-Mailer> = 'Keayl' });

Translated subjects

When an action omits :subject and the mailer has an i18n backend, the subject is looked up at <mailer-path>.<action>.subject and interpolated with the view locals:

en:
  notice_mailer:
    welcome:
      subject: "Welcome, %{name}"

The message

MVC::Keayl::Mail holds from, to, cc, bcc, reply-to, subject, the html-part and text-part, custom headers, and attachments. encoded serializes it to an RFC-822 message, using multipart/alternative for a text and an html part, wrapped in multipart/mixed when there are attachments.

Attachments

An action populates attachments before calling mail. Assign a string or Blob of content, or a hash with content-type and content. The content type is inferred from the filename when not given. attachments.inline marks an attachment inline and gives it a Content-ID for referencing from the body:

method newsletter {
  self.attachments<report.pdf> = $pdf-bytes;
  self.attachments.inline<logo.png> = %( content-type => 'image/png', content => $png-bytes );
  self.mail(to => '[email protected]', subject => 'This week');
}

Async delivery

deliver-later enqueues a delivery job through the configured job queue instead of sending inline. When the job runs, it delivers the message:

$mailer.deliver-later('welcome', $user);

Interceptors and observers

Interceptors run before delivery and may rewrite the message (redirecting all mail in staging, for example). Observers run after delivery. Each is a callable taking the mail, or an object with a delivering-email / delivered-email method:

MVC::Keayl::Mailer.register-interceptor(-> $mail { $mail.to = ['[email protected]'] });
MVC::Keayl::Mailer.register-observer(-> $mail { log-delivery($mail) });

Previews

A preview class subclasses MVC::Keayl::Mailer::Preview with a method per sample message that builds and returns a mail. Register it, and PreviewController serves an index and the rendered parts at a dev route:

class NoticePreview is Preview {
  method welcome { NoticeMailer.new(view-renderer => $view).build('welcome', $sample-user) }
}
Previews.register('notice_mailer', NoticePreview);

PreviewController#show reads preview, email, and part params and renders the html part (the default), the text part, or the raw encoded message.

Delivery

A delivery is any MVC::Keayl::Mailer::Delivery (a role with one deliver(Mail) method). Three are built in:

  • Test (MVC::Keayl::Mailer::Delivery::Test) collects messages in a process-wide list for assertions. deliveries reads them, clear empties it.

  • File (MVC::Keayl::Mailer::Delivery::File) writes each encoded message to a numbered .eml file under its directory.

  • SMTP (MVC::Keayl::Mailer::Delivery::SMTP) builds the envelope (host, port, from, to, data) and hands it to a pluggable transport callable, which performs the actual send.

my $delivery = MVC::Keayl::Mailer::Delivery::SMTP.new(
  host      => 'mail.example.com',
  port      => 587,
  transport => -> %envelope { send-over-smtp(%envelope) },
);

MVC::Keayl v0.9.1

Model-View-Controller web framework

Authors

  • Greg Donald

License

Artistic-2.0

Dependencies

Cro::HTTPCrypt::RandomDigest::HMACDigest::SHA1::NativeOpenSSLMIME::Base64YAMLishORM::ActiveRecord:auth<zef:gdonald>Template::HAML:auth<zef:gdonald>

Provides

  • MVC::Keayl
  • MVC::Keayl::APIController
  • MVC::Keayl::ActionText
  • MVC::Keayl::ActionText::Repository
  • MVC::Keayl::ActionText::RichTextable
  • MVC::Keayl::Adapter
  • MVC::Keayl::Adapter::Cro
  • MVC::Keayl::Adapter::Test
  • MVC::Keayl::Application
  • MVC::Keayl::Assets
  • MVC::Keayl::Assets::Serving
  • MVC::Keayl::CLI
  • MVC::Keayl::CSRF
  • MVC::Keayl::Cable::Broadcasting
  • MVC::Keayl::Cable::Channel
  • MVC::Keayl::Cable::Connection
  • MVC::Keayl::Cable::PubSub
  • MVC::Keayl::Cable::PubSub::External
  • MVC::Keayl::Cable::PubSub::InMemory
  • MVC::Keayl::Cache
  • MVC::Keayl::Caching
  • MVC::Keayl::Config
  • MVC::Keayl::Controller
  • MVC::Keayl::Cookies
  • MVC::Keayl::Credentials
  • MVC::Keayl::Dispatcher
  • MVC::Keayl::Endpoint
  • MVC::Keayl::Engine
  • MVC::Keayl::ErrorReporter
  • MVC::Keayl::ErrorReporting
  • MVC::Keayl::Errors
  • MVC::Keayl::ExceptionPage
  • MVC::Keayl::Flash
  • MVC::Keayl::HealthController
  • MVC::Keayl::Helpers::Asset
  • MVC::Keayl::Helpers::DateTime
  • MVC::Keayl::Helpers::Form
  • MVC::Keayl::Helpers::Number
  • MVC::Keayl::Helpers::Options
  • MVC::Keayl::Helpers::Tag
  • MVC::Keayl::Helpers::Text
  • MVC::Keayl::Helpers::Url
  • MVC::Keayl::HttpAuthentication
  • MVC::Keayl::I18n
  • MVC::Keayl::I18n::Locale
  • MVC::Keayl::I18n::Pluralization
  • MVC::Keayl::Job
  • MVC::Keayl::Job::GlobalID
  • MVC::Keayl::Job::QueueAdapter
  • MVC::Keayl::Job::QueueAdapter::Async
  • MVC::Keayl::Job::QueueAdapter::Database
  • MVC::Keayl::Job::QueueAdapter::Inline
  • MVC::Keayl::Job::QueueAdapter::Test
  • MVC::Keayl::Live
  • MVC::Keayl::LogEvent
  • MVC::Keayl::Logger
  • MVC::Keayl::Mail
  • MVC::Keayl::Mailbox
  • MVC::Keayl::Mailbox::Ingress
  • MVC::Keayl::Mailbox::Router
  • MVC::Keayl::Mailer
  • MVC::Keayl::Mailer::Delivery
  • MVC::Keayl::Mailer::Delivery::File
  • MVC::Keayl::Mailer::Delivery::SMTP
  • MVC::Keayl::Mailer::Delivery::Test
  • MVC::Keayl::Mailer::DeliveryJob
  • MVC::Keayl::Mailer::Preview
  • MVC::Keayl::Middleware
  • MVC::Keayl::Middleware::Database
  • MVC::Keayl::Middleware::HostAuthorization
  • MVC::Keayl::Middleware::Logger
  • MVC::Keayl::Middleware::RequestId
  • MVC::Keayl::Middleware::SSL
  • MVC::Keayl::Middleware::SecureHeaders
  • MVC::Keayl::Middleware::Static
  • MVC::Keayl::MiddlewareStack
  • MVC::Keayl::Mime
  • MVC::Keayl::Notifications
  • MVC::Keayl::PWAController
  • MVC::Keayl::ParameterFilter
  • MVC::Keayl::Parameters
  • MVC::Keayl::Params
  • MVC::Keayl::Request
  • MVC::Keayl::Response
  • MVC::Keayl::Router
  • MVC::Keayl::Routing
  • MVC::Keayl::Routing::Mount
  • MVC::Keayl::Routing::PathPattern
  • MVC::Keayl::Routing::Redirect
  • MVC::Keayl::Routing::Resources
  • MVC::Keayl::Routing::Route
  • MVC::Keayl::Routing::RouteMatch
  • MVC::Keayl::Routing::UrlHelpers
  • MVC::Keayl::SafeString
  • MVC::Keayl::Secrets
  • MVC::Keayl::Session
  • MVC::Keayl::Storage
  • MVC::Keayl::Storage::Attached
  • MVC::Keayl::Storage::Repository
  • MVC::Keayl::Storage::Service
  • MVC::Keayl::Storage::Serving
  • MVC::Keayl::Storage::Variant
  • MVC::Keayl::TestSupport
  • MVC::Keayl::View
  • MVC::Keayl::View::Context
  • MVC::Keayl::View::Handler
  • MVC::Keayl::View::Handler::HAML

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.