Hanami::Mailer
Mail for Ruby applications.
Version
This branch contains the code for hanami-mailer 2.x.
Rubies
Hanami::Mailer supports Ruby (MRI) 3.0+
Installation
Add this line to your application's Gemfile:
And then execute:
$ bundle
Or install it yourself as:
$ gem install hanami-mailer
Usage
Conventions
- Templates are searched under
Hanami::Mailer::Configuration#root, set this value according to your app structure (eg."app/templates"). - A mailer will look for a template with a file name that is composed by its full class name (eg.
"articles/index"). - A template must have two concatenated extensions: one for the format and one for the engine (eg.
".html.erb"). - The framework must be loaded before rendering the first time:
Hanami::Mailer.finalize(configuration).
Mailers
A simple mailer looks like this:
# Create two files: `invoice.html.erb` and `invoice.txt.erb`
configuration = Hanami::Mailer::Configuration.new do
config.delivery_method = :test
end
from "noreply@example.com"
to ->(locals) { locals.fetch(:user).email }
end
configuration = Hanami::Mailer.finalize(configuration)
invoice = OpenStruct.new(number: 23)
mailer = InvoiceMailer.new(configuration: configuration)
mail = mailer.deliver(invoice: invoice)
mail
# => #<Mail::Message:70303354246540, Multipart: true, Headers: <Date: Wed, 22 Mar 2017 11:48:57 +0100>, <From: noreply@example.com>, <To: user@example.com>, <Cc: >, <Bcc: >, <Message-ID: <58d25699e47f9_b4e13ff0c503e4f4632e6@escher.mail>>, <Subject: >, <Mime-Version: 1.0>, <Content-Type: multipart/alternative; boundary=--==_mimepart_58d25699e42d2_b4e13ff0c503e4f463186>, <Content-Transfer-Encoding: 7bit>>
mail.to_s
# =>
# From: noreply@example.com
# To: user@example.com
# Message-ID: <58d25699e47f9_b4e13ff0c503e4f4632e6@escher.mail>
# Subject:
# Mime-Version: 1.0
# Content-Type: multipart/alternative;
# boundary="--==_mimepart_58d25699e42d2_b4e13ff0c503e4f463186";
# charset=UTF-8
# Content-Transfer-Encoding: 7bit
#
#
# ----==_mimepart_58d25699e42d2_b4e13ff0c503e4f463186
# Content-Type: text/plain;
# charset=UTF-8
# Content-Transfer-Encoding: 7bit
#
# Invoice #23
#
# ----==_mimepart_58d25699e42d2_b4e13ff0c503e4f463186
# Content-Type: text/html;
# charset=UTF-8
# Content-Transfer-Encoding: 7bit
#
# <html>
# <body>
# <h1>Invoice template</h1>
# </body>
# </html>
#
# ----==_mimepart_58d25699e42d2_b4e13ff0c503e4f463186--
A mailer with .to and .from addresses and mailer delivery:
configuration = Hanami::Mailer::Configuration.new do
config.delivery_method = :smtp,
address: "smtp.gmail.com",
port: 587,
domain: "example.com",
user_name: ,
password: ,
authentication: "plain",
enable_starttls_auto: true
end
return_path 'bounce@sender.com'
from 'noreply@sender.com'
to 'noreply@recipient.com'
cc 'cc@sender.com'
bcc 'alice@example.com'
subject 'Welcome'
end
WelcomeMailer.new(configuration: configuration).call(locals)
Locals
The set of objects passed in the deliver call are called locals and are available inside the mailer and the template.
user = OpenStruct.new(name: Luca', email: 'user@hanamirb.org')
class WelcomeMailer < Hanami::Mailer
from 'noreply@sender.com'
subject 'Welcome'
to ->(locals) { locals.fetch(:user).email }
end
WelcomeMailer.new(configuration: configuration).deliver(user: luca)
The corresponding erb file:
Hello !
Scope
All public methods defined in the mailer are accessible from the template:
from 'noreply@sender.com'
to 'noreply@recipient.com'
subject 'Welcome'
'Ahoy'
end
end
Template
The template file must be located under the relevant root and must match the inflected snake case of the mailer class name.
# Given this root
configuration.root # => #<Pathname:app/templates>
# For InvoiceMailer, it looks for:
# * app/templates/invoice_mailer.html.erb
# * app/templates/invoice_mailer.txt.erb
If we want to specify a different template, we can do:
template 'invoice'
end
# It will look for:
# * app/templates/invoice.html.erb
# * app/templates/invoice.txt.erb
Engines
The builtin rendering engine is ERb.
This is the list of the supported engines.
They are listed in order of higher precedence, for a given extension.
For instance, if ERubis is loaded, it will be preferred over ERb to render .erb templates.
| Engine | Extensions |
|---|---|
| Erubis | erb, rhtml, erubis |
| ERb | erb, rhtml |
| Redcarpet | markdown, mkd, md |
| RDiscount | markdown, mkd, md |
| Kramdown | markdown, mkd, md |
| Maruku | markdown, mkd, md |
| BlueCloth | markdown, mkd, md |
| Asciidoctor | ad, adoc, asciidoc |
| Builder | builder |
| CSV | rcsv |
| CoffeeScript | coffee |
| WikiCloth | wiki, mediawiki, mw |
| Creole | wiki, creole |
| Etanni | etn, etanni |
| Haml | haml |
| Less | less |
| Liquid | liquid |
| Markaby | mab |
| Nokogiri | nokogiri |
| Plain | html |
| RDoc | rdoc |
| Radius | radius |
| RedCloth | textile |
| Sass | sass |
| Scss | scss |
| Slim | slim |
| String | str |
| Yajl | yajl |
Configuration
Hanami::Mailer can be configured with a DSL that determines its behavior.
It supports a few options:
configuration = Hanami::Mailer::Configuration.new do
# Set the root path where to search for templates
# Argument: String, Pathname, #to_pathname, defaults to the current directory
#
config.root = "path/to/root"
# Set the default charset for emails
# Argument: String, defaults to "UTF-8"
#
config.default_charset = "iso-8859"
# Set the delivery method
# Argument: Symbol
# Argument: Hash, optional configurations
config.delivery_method = :smtp
end
Attachments
Attachments can be added with the following API:
# ...
before do
mail.attachments["invoice-.pdf"] = 'path/to/invoice.pdf'
end
end
Delivery Method
The global delivery method is defined through the Hanami::Mailer configuration, as:
configuration = Hanami::Mailer::Configuration.new do
config.delivery_method = :smtp
end
configuration = Hanami::Mailer::Configuration.new do
config.delivery_method = :smtp, { address: "localhost", port: 1025 }
end
Builtin options are:
- Exim (
:exim) - Sendmail (
:sendmail) - SMTP (
:smtp, for local installations) - SMTP Connection (
:smtp_connection, viaNet::SMTP- for remote installations) - Test (
:test, for testing purposes)
Custom Delivery Method
Developers can specify their own custom delivery policy:
@options = options
end
# ...
end
end
configuration = Hanami::Mailer::Configuration.new do
config.delivery_method = MandrillDeliveryMethod,
username: ,
password:
end
The class passed to .delivery_method= must accept an optional set of options
with the constructor (#initialize) and respond to #deliver!.
Multipart Delivery
All the email are sent as multipart messages by default.
For a given mailer, the framework looks up for associated text (.txt) and HTML (.html) templates and render them.
InvoiceMailer.new(configuration: configuration).deliver({}) # delivers both text and html templates
InvoiceMailer.new(configuration: configuration).deliver(format: :txt) # delivers only text template
Please note that they aren't both mandatory, but at least one of them MUST be present.