hanami-mailer/README.md

457 lines
11 KiB
Markdown
Raw Permalink Normal View History

2016-01-20 15:17:21 +00:00
# Hanami::Mailer
2015-06-29 07:05:46 +00:00
Mail for Ruby applications.
2021-06-15 10:51:29 +00:00
## Version
**This branch contains the code for `hanami-mailer` 2.x.**
2015-06-29 07:05:46 +00:00
## Status
2018-07-24 10:03:38 +00:00
[![Gem Version](https://badge.fury.io/rb/hanami-mailer.svg)](https://badge.fury.io/rb/hanami-mailer)
2021-06-15 10:51:29 +00:00
[![CI](https://github.com/hanami/mailer/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/mailer/actions?query=workflow%3Aci+branch%3Amain)
[![Test Coverage](https://codecov.io/gh/hanami/mailer/branch/main/graph/badge.svg)](https://codecov.io/gh/hanami/mailer)
2018-07-24 10:03:38 +00:00
[![Depfu](https://badges.depfu.com/badges/739c6e10eaf20d3ba4240d00828284db/overview.svg)](https://depfu.com/github/hanami/mailer?project=Bundler)
2016-01-20 15:17:21 +00:00
[![Inline Docs](http://inch-ci.org/github/hanami/mailer.svg)](http://inch-ci.org/github/hanami/mailer)
2015-06-29 07:05:46 +00:00
## Contact
2016-01-20 15:17:21 +00:00
* 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
2015-06-29 07:05:46 +00:00
## Rubies
__Hanami::Mailer__ supports Ruby (MRI) 3.0+
2015-06-29 07:05:46 +00:00
## Installation
Add this line to your application's Gemfile:
```ruby
2016-01-20 15:17:21 +00:00
gem 'hanami-mailer'
2015-06-29 07:05:46 +00:00
```
And then execute:
$ bundle
Or install it yourself as:
2016-01-20 15:17:21 +00:00
$ gem install hanami-mailer
2015-06-29 07:05:46 +00:00
## Usage
2015-08-28 14:31:56 +00:00
### Conventions
* Templates are searched under `Hanami::Mailer::Configuration#root`, set this value according to your app structure (eg. `"app/templates"`).
2015-08-28 14:31:56 +00:00
* 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)`.
2015-08-28 14:31:56 +00:00
### Mailers
A simple mailer looks like this:
```ruby
2016-01-20 15:17:21 +00:00
require 'hanami/mailer'
require 'ostruct'
2015-08-28 14:31:56 +00:00
# Create two files: `invoice.html.erb` and `invoice.txt.erb`
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = :test
end
class Invoice < Hanami::Mailer
from "noreply@example.com"
to ->(locals) { locals.fetch(:user).email }
2015-08-28 14:31:56 +00:00
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--
2015-08-28 14:31:56 +00:00
```
2015-09-23 18:15:20 +00:00
A mailer with `.to` and `.from` addresses and mailer delivery:
2015-08-28 14:31:56 +00:00
```ruby
2016-01-20 15:17:21 +00:00
require 'hanami/mailer'
2015-08-28 14:31:56 +00:00
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
2020-02-03 11:00:28 +00:00
return_path 'bounce@sender.com'
from 'noreply@sender.com'
to 'noreply@recipient.com'
cc 'cc@sender.com'
2016-05-05 21:35:34 +00:00
bcc 'alice@example.com'
2015-08-28 14:31:56 +00:00
subject 'Welcome'
end
WelcomeMailer.new(configuration: configuration).call(locals)
2015-08-28 14:31:56 +00:00
```
### Locals
The set of objects passed in the `deliver` call are called `locals` and are available inside the mailer and the template.
2015-08-28 14:31:56 +00:00
```ruby
2016-01-20 15:17:21 +00:00
require 'hanami/mailer'
require 'ostruct'
2015-08-28 14:31:56 +00:00
user = OpenStruct.new(name: Luca', email: 'user@hanamirb.org')
2015-09-23 18:15:20 +00:00
class WelcomeMailer < Hanami::Mailer
2015-09-23 18:15:20 +00:00
from 'noreply@sender.com'
subject 'Welcome'
to ->(locals) { locals.fetch(:user).email }
2015-08-28 14:31:56 +00:00
end
WelcomeMailer.new(configuration: configuration).deliver(user: luca)
2015-08-28 14:31:56 +00:00
```
2015-08-28 14:41:59 +00:00
The corresponding `erb` file:
2015-08-28 14:31:56 +00:00
```erb
Hello <%= user.name %>!
2015-08-28 14:31:56 +00:00
```
### Scope
2015-09-23 18:15:20 +00:00
All public methods defined in the mailer are accessible from the template:
2015-08-28 14:31:56 +00:00
```ruby
2016-01-20 15:17:21 +00:00
require 'hanami/mailer'
2015-08-28 14:31:56 +00:00
class WelcomeMailer < Hanami::Mailer
2015-09-23 18:15:20 +00:00
from 'noreply@sender.com'
to 'noreply@recipient.com'
2015-08-28 14:31:56 +00:00
subject 'Welcome'
2015-08-28 14:31:56 +00:00
def greeting
'Ahoy'
end
end
```
```erb
<h2><%= greeting %></h2>
```
### Template
The template file must be located under the relevant `root` and must match the inflected snake case of the mailer class name.
2015-08-28 14:31:56 +00:00
```ruby
2015-09-23 18:15:20 +00:00
# Given this root
configuration.root # => #<Pathname:app/templates>
2015-09-23 18:15:20 +00:00
# For InvoiceMailer, it looks for:
# * app/templates/invoice_mailer.html.erb
# * app/templates/invoice_mailer.txt.erb
2015-08-28 14:31:56 +00:00
```
2015-09-23 18:15:20 +00:00
If we want to specify a different template, we can do:
2015-08-28 14:31:56 +00:00
```ruby
class InvoiceMailer < Hanami::Mailer
2015-09-23 18:15:20 +00:00
template 'invoice'
2015-08-28 14:31:56 +00:00
end
2015-09-23 18:15:20 +00:00
# It will look for:
# * app/templates/invoice.html.erb
# * app/templates/invoice.txt.erb
2015-08-28 14:31:56 +00:00
```
### Engines
The builtin rendering engine is [ERb](http://en.wikipedia.org/wiki/ERuby).
2015-09-23 18:15:20 +00:00
This is the list of the supported engines.
They are listed in order of **higher precedence**, for a given extension.
For instance, if [ERubis](http://www.kuwata-lab.com/erubis/) is loaded, it will be preferred over ERb to render `.erb` templates.
<table>
<tr>
<th>Engine</th>
<th>Extensions</th>
</tr>
<tr>
<td>Erubis</td>
<td>erb, rhtml, erubis</td>
</tr>
<tr>
<td>ERb</td>
<td>erb, rhtml</td>
</tr>
<tr>
<td>Redcarpet</td>
<td>markdown, mkd, md</td>
</tr>
<tr>
<td>RDiscount</td>
<td>markdown, mkd, md</td>
</tr>
<tr>
<td>Kramdown</td>
<td>markdown, mkd, md</td>
</tr>
<tr>
<td>Maruku</td>
<td>markdown, mkd, md</td>
</tr>
<tr>
<td>BlueCloth</td>
<td>markdown, mkd, md</td>
</tr>
<tr>
<td>Asciidoctor</td>
<td>ad, adoc, asciidoc</td>
</tr>
<tr>
<td>Builder</td>
<td>builder</td>
</tr>
<tr>
<td>CSV</td>
<td>rcsv</td>
</tr>
<tr>
<td>CoffeeScript</td>
<td>coffee</td>
</tr>
<tr>
<td>WikiCloth</td>
<td>wiki, mediawiki, mw</td>
</tr>
<tr>
<td>Creole</td>
<td>wiki, creole</td>
</tr>
<tr>
<td>Etanni</td>
<td>etn, etanni</td>
</tr>
<tr>
<td>Haml</td>
<td>haml</td>
</tr>
<tr>
<td>Less</td>
<td>less</td>
</tr>
<tr>
<td>Liquid</td>
<td>liquid</td>
</tr>
<tr>
<td>Markaby</td>
<td>mab</td>
</tr>
<tr>
<td>Nokogiri</td>
<td>nokogiri</td>
</tr>
<tr>
<td>Plain</td>
<td>html</td>
</tr>
<tr>
<td>RDoc</td>
<td>rdoc</td>
</tr>
<tr>
<td>Radius</td>
<td>radius</td>
</tr>
<tr>
<td>RedCloth</td>
<td>textile</td>
</tr>
<tr>
<td>Sass</td>
<td>sass</td>
</tr>
<tr>
<td>Scss</td>
<td>scss</td>
</tr>
<tr>
<td>Slim</td>
<td>slim</td>
</tr>
<tr>
<td>String</td>
<td>str</td>
</tr>
<tr>
<td>Yajl</td>
<td>yajl</td>
</tr>
</table>
2015-08-28 14:31:56 +00:00
### Configuration
2016-01-20 15:17:21 +00:00
__Hanami::Mailer__ can be configured with a DSL that determines its behavior.
2015-08-28 14:31:56 +00:00
It supports a few options:
```ruby
2018-07-24 10:12:21 +00:00
require "hanami/mailer"
2015-08-28 14:31:56 +00:00
configuration = Hanami::Mailer::Configuration.new do |config|
2015-08-28 14:31:56 +00:00
# Set the root path where to search for templates
# Argument: String, Pathname, #to_pathname, defaults to the current directory
#
2018-07-24 10:12:21 +00:00
config.root = "path/to/root"
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
# Set the default charset for emails
# Argument: String, defaults to "UTF-8"
2015-08-28 14:31:56 +00:00
#
2018-07-24 10:12:21 +00:00
config.default_charset = "iso-8859"
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
# Set the delivery method
# Argument: Symbol
# Argument: Hash, optional configurations
config.delivery_method = :stmp
end
2015-08-28 14:31:56 +00:00
```
2015-09-23 18:15:20 +00:00
### Attachments
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
Attachments can be added with the following API:
2015-08-28 14:31:56 +00:00
```ruby
class InvoiceMailer < Hanami::Mailer
2015-09-23 18:15:20 +00:00
# ...
before do |mail, locals|
mail.attachments["invoice-#{locals.fetch(:invoice).number}.pdf"] = 'path/to/invoice.pdf'
2015-08-28 14:31:56 +00:00
end
end
```
2015-09-23 18:15:20 +00:00
### Delivery Method
2015-08-28 14:31:56 +00:00
2016-01-20 15:17:21 +00:00
The global delivery method is defined through the __Hanami::Mailer__ configuration, as:
2015-08-28 14:31:56 +00:00
```ruby
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = :smtp
2015-08-28 14:31:56 +00:00
end
```
```ruby
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = :smtp, { address: "localhost", port: 1025 }
2015-08-28 14:31:56 +00:00
end
```
2015-09-23 18:15:20 +00:00
Builtin options are:
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
* Exim (`:exim`)
* Sendmail (`:sendmail`)
* SMTP (`:smtp`, for local installations)
* SMTP Connection (`:smtp_connection`, via `Net::SMTP` - for remote installations)
* Test (`:test`, for testing purposes)
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
### Custom Delivery Method
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
Developers can specify their own custom delivery policy:
2015-08-28 14:31:56 +00:00
```ruby
2016-01-20 15:17:21 +00:00
require 'hanami/mailer'
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
class MandrillDeliveryMethod
def initialize(options)
@options = options
2015-08-28 14:31:56 +00:00
end
2015-09-21 11:44:26 +00:00
2015-09-23 18:15:20 +00:00
def deliver!(mail)
# ...
end
2015-08-28 14:31:56 +00:00
end
configuration = Hanami::Mailer::Configuration.new do |config|
config.delivery_method = MandrillDeliveryMethod,
username: ENV['MANDRILL_USERNAME'],
password: ENV['MANDRILL_API_KEY']
end
2015-08-28 14:31:56 +00:00
```
The class passed to `.delivery_method=` must accept an optional set of options
2015-09-23 18:15:20 +00:00
with the constructor (`#initialize`) and respond to `#deliver!`.
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
### Multipart Delivery
2015-08-28 14:31:56 +00:00
2015-09-23 18:15:20 +00:00
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.
2015-08-28 14:31:56 +00:00
```ruby
InvoiceMailer.new(configuration: configuration).deliver({}) # delivers both text and html templates
InvoiceMailer.new(configuration: configuration).deliver(format: :txt) # delivers only text template
2015-08-28 14:31:56 +00:00
```
2015-09-23 18:15:20 +00:00
Please note that **they aren't both mandatory, but at least one of them MUST** be present.
2015-06-29 07:05:46 +00:00
## Versioning
2016-01-20 15:17:21 +00:00
__Hanami::Mailer__ uses [Semantic Versioning 2.0.0](http://semver.org)
2015-06-29 07:05:46 +00:00
## Copyright
2021-01-14 11:43:52 +00:00
Copyright © 2015-2021 Luca Guidi Released under MIT License
2016-01-22 14:02:10 +00:00
2016-01-20 15:17:21 +00:00
This project was formerly known as Lotus (`lotus-mailer`).