Mail for Ruby applications.
This branch contains the code for hanami-mailer
2.x.
- Home page: http://hanamirb.org
- Mailing List: http://hanamirb.org/mailing-list
- API Doc: http://rdoc.info/gems/hanami-mailer
- Bugs/Issues: https://github.com/hanami/mailer/issues
- Support: http://stackoverflow.com/questions/tagged/hanami
- Chat: http://chat.hanamirb.org
Hanami::Mailer supports Ruby (MRI) 3.0+
Add this line to your application's Gemfile:
gem 'hanami-mailer'
And then execute:
$ bundle
Or install it yourself as:
$ gem install hanami-mailer
- 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)
.
A simple mailer looks like this:
require 'hanami/mailer'
require 'ostruct'
# Create two files: `invoice.html.erb` and `invoice.txt.erb`
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = :test
end
class InvoiceMailer < Hanami::Mailer
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:
require 'hanami/mailer'
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = :smtp,
address: "smtp.gmail.com",
port: 587,
domain: "example.com",
user_name: ENV['SMTP_USERNAME'],
password: ENV['SMTP_PASSWORD'],
authentication: "plain",
enable_starttls_auto: true
end
class WelcomeMailer < Hanami::Mailer
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)
The set of objects passed in the deliver
call are called locals
and are available inside the mailer and the template.
require 'hanami/mailer'
require 'ostruct'
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 <%= user.name %>!
All public methods defined in the mailer are accessible from the template:
require 'hanami/mailer'
class WelcomeMailer < Hanami::Mailer
from 'noreply@sender.com'
to 'noreply@recipient.com'
subject 'Welcome'
def greeting
'Ahoy'
end
end
<h2><%= greeting %></h2>
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:
class InvoiceMailer < Hanami::Mailer
template 'invoice'
end
# It will look for:
# * app/templates/invoice.html.erb
# * app/templates/invoice.txt.erb
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 |
Hanami::Mailer can be configured with a DSL that determines its behavior. It supports a few options:
require "hanami/mailer"
configuration = Hanami::Mailer::Configuration.new do |config|
# 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 can be added with the following API:
class InvoiceMailer < Hanami::Mailer
# ...
before do |mail, locals|
mail.attachments["invoice-#{locals.fetch(:invoice).number}.pdf"] = 'path/to/invoice.pdf'
end
end
The global delivery method is defined through the Hanami::Mailer configuration, as:
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = :smtp
end
configuration = Hanami::Mailer::Configuration.new do |config|
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)
Developers can specify their own custom delivery policy:
require 'hanami/mailer'
class MandrillDeliveryMethod
def initialize(options)
@options = options
end
def deliver!(mail)
# ...
end
end
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = MandrillDeliveryMethod,
username: ENV['MANDRILL_USERNAME'],
password: ENV['MANDRILL_API_KEY']
end
The class passed to .delivery_method=
must accept an optional set of options
with the constructor (#initialize
) and respond to #deliver!
.
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.
Hanami::Mailer uses Semantic Versioning 2.0.0
Copyright © 2015-2021 Luca Guidi – Released under MIT License
This project was formerly known as Lotus (lotus-mailer
).