MultiMail: Easily switch email APIs
Many providers offer APIs to send, receive, and parse email. MultiMail lets you easily switch between these APIs, and integrates tightly with the Mail gem.
- Cloudmailin: Example
- Mailgun: Example
- Mandrill: Example
- Postmark: Example
- SendGrid: Example
- MTA like Postfix or qmail: Example
Usage
Incoming
require 'multi_mail'
# Create an object to consume the webhook data.
service = MultiMail::Receiver.new(:provider => 'mandrill')
# Process the webhook data, whether it's raw POST data, a params hash, a Rack request, etc.
messages = service.process(data)
messages
will be an array of Mail::Message instances.
Any non-standard parameters provided by an API are added to each message as an instance variable. For example, Mailgun provides stripped-text
, which is the message body without quoted parts or signature block. You can access it as message.stripped_text
. The instance variable is the non-standard parameter in lowercase with underscores instead of hyphens.
Outgoing
With MultiMail, you send a message the same way you do with the Mail gem. Just set delivery_method
:
require 'multi_mail'
message = Mail.new do
delivery_method MultiMail::Sender::Postmark, :api_key => 'your-api-key'
to 'user@wookiecookies.com'
from 'Chewbacca <chewy@wookiecookies.com>'
subject 'How About Some Cookies?'
text_part do
body 'I am just some plain text!'
end
html_part do
content_type 'text/html; charset=UTF-8'
body '<html><body><h1>I am a header</h1><p>And I am a paragraph</p></body></html>'
end
end
message.deliver
Alternatively, instead of setting delivery_method
during initialization, you can set it before delivery:
message = Mail.new do
to 'user@wookiecookies.com'
from 'Chewbacca <chewy@wookiecookies.com>'
subject 'How About Some Cookies?'
text_part do
body 'I am just some plain text!'
end
html_part do
content_type 'text/html; charset=UTF-8'
body '<html><body><h1>I am a header</h1><p>And I am a paragraph</p></body></html>'
end
end
message.delivery_method MultiMail::Sender::Postmark, :api_key => 'your-api-key'
message.deliver
Or, if you are sending many messages, you can set a default delivery_method
for all messages:
Mail.defaults do
delivery_method MultiMail::Sender::Postmark, :api_key => 'your-api-key'
end
ActionMailer
First, add the delivery method to ActionMailer:
ActionMailer::Base.add_delivery_method :mandrill, MultiMail::Sender::Mandrill, :api_key => 'your-api-key'
Set the default delivery method for all ActionMailer classes in config/environments/<ENV>.rb
:
config.action_mailer.delivery_method = :mandrill
Or, set the delivery method in an ActionMailer class:
class UserMailer < ActionMailer::Base
default :delivery_method => :mandrill
end
Or, set the delivery method in an ActionMailer method:
class UserMailer < ActionMailer::Base
def welcome_email(user)
mail({
:to => user.email,
:subject => 'Welcome to My Awesome Site',
:delivery_method => :mandrill,
})
end
end
Set the delivery method's default options for all ActionMailer classes in config/environments/<ENV>.rb
:
config.action_mailer.mandrill_settings = {:api_key => 'your-api-key', :template_name => 'default'}
Or, set the delivery method's options in an ActionMailer method:
class UserMailer < ActionMailer::Base
def welcome_email(mail)
mail({
:to => user.email,
:subject => 'Welcome to My Awesome Site',
:delivery_method_options => {:template_name => 'default'},
})
end
end
Or, set the delivery method's options in an ActionMailer action:
class UserMailer < ActionMailer::Base
before_action :set_delivery_method_options
...
private
def set_delivery_method_options
mail.delivery_method.template_name = 'default'
end
end
Tagging
Mailgun, Mandrill and Postmark allow you to tag messages in order to accumulate statistics by tag, which will be accessible through their user interface:
require 'multi_mail'
message = Mail.new do
delivery_method MultiMail::Sender::Mandrill, :api_key => 'your-api-key'
tag 'signup'
tag 'promotion'
...
end
message.deliver
Mailgun accepts at most 3 tags and Postmark at most one tag.
Track opens and clicks
Mailgun, Mandrill and Postmark allow you to set open tracking, and Mailgun and Mandrill allow you to set click tracking on a per-message basis:
require 'multi_mail'
message = Mail.new do
delivery_method MultiMail::Sender::Mailgun,
:api_key => 'your-api-key',
:domain => 'your-domain.mailgun.org',
:track => {
:opens => true,
:clicks => false,
}
...
end
message.deliver
Mailgun and Mandrill track whether a recipient has clicked a link in a message by rewriting its URL. If want to rewrite URLs in HTML parts only (leaving URLs as-is in text parts) use :clicks => 'htmlonly'
if you are using Mailgun; if you are using Mandrill, do not set :clicks
and instead configure click tracking globally in your Mandrill sending options.
Inspect the API response
Pass :return_response => true
to delivery_method
and use the deliver!
method to send the message:
message = Mail.new do
delivery_method MultiMail::Sender::Postmark, :api_key => 'your-api-key', :return_response => true
...
end
message.deliver!
Note that the deliver!
method ignores Mail's perform_deliveries
and raise_delivery_errors
flags.
Cloudmailin
Incoming
service = MultiMail::Receiver.new({
:provider => 'cloudmailin',
})
The default HTTP POST format is raw
. Add a :http_post_format
option to change the HTTP POST format, with possible values of "multipart"
, "json"
or "raw"
(default):
service = MultiMail::Receiver.new({
:provider => 'cloudmailin',
:http_post_format => 'raw',
})
If you are using an Amazon S3 attachment store, add a :attachment_store => true
option. You must set the attachment store's permission setting to "Public Read".
service = MultiMail::Receiver.new({
:provider => 'cloudmailin',
:http_post_format => 'multipart',
:attachment_store => true,
})
See Cloudmailin's documentation for these additional parameters provided by the API:
reply_plain
spf-result
Mailgun
Incoming
service = MultiMail::Receiver.new({
:provider => 'mailgun',
})
To check that a request originates from Mailgun, add a :mailgun_api_key
option:
service = MultiMail::Receiver.new({
:provider => 'mailgun',
:mailgun_api_key => 'key-xxxxxxxxxxxxxxxxxxxxxxx-x-xxxxxx',
})
If you are using the raw MIME format, add a :http_post_format => 'raw'
option:
service = MultiMail::Receiver.new({
:provider => 'mailgun',
:http_post_format => 'raw',
})
See Mailgun's documentation for these additional parameters provided by the API:
stripped-text
stripped-signature
stripped-html
content-id-map
Outgoing
Mail.deliver do
delivery_method MultiMail::Sender::Mailgun, :api_key => 'your-api-key', :domain => 'your-domain.mailgun.org'
to _to_
from _from_
subject _subject_
text_part do
body _text_
end
html_part do
content_type 'text/html; charset=UTF-8'
body _html_
end
end
You may pass additional arguments to delivery_method
to use Mailgun-specific features (see docs):
o:campaign
o:dkim
o:deliverytime
o:testmode
o:tracking
v:
Mail.deliver do
delivery_method MultiMail::Sender::Mailgun, :api_key => 'your-api-key', :domain => 'your-domain.mailgun.org',
:o:campaign => 'campaign', :o:dkim => 'yes (or no)',...
...
end
Mandrill
Incoming
service = MultiMail::Receiver.new({
:provider => 'mandrill',
})
To check that a request originates from Mandrill, add :mandrill_webhook_key
and :mandrill_webhook_url
options (you can get your webhook key from Mandrill's Webhooks Settings):
service = MultiMail::Receiver.new({
:provider => 'mandrill',
:mandrill_webhook_key => 'xxxxxxxxxxxxxxxxxxxxxx',
:mandrill_webhook_url => 'http://example.com/post',
})
The default SpamAssassin score needed to flag an email as spam is 5
. Add a :spamassassin_threshold
option to increase or decrease it:
service = MultiMail::Receiver.new({
:provider => 'mandrill',
:spamassassin_threshold => 4.5,
})
See Mandrill's documentation for these additional parameters provided by the API:
ts
email
dkim-signed
dkim-valid
spam_report-score
spf-result
Outgoing
Mail.deliver do
delivery_method MultiMail::Sender::Mandrill, :api_key => 'your-api-key'
to _to_
from _from_email_ + _from_name_
subject _subject_
text_part do
body _text_
end
html_part do
content_type 'text/html; charset=UTF-8'
body _html_
end
end
You may pass additional arguments to delivery_method
to use Mandrill-specific features (see docs):
important
-
auto_text
andauto_html
inline_css
url_strip_qs
preserve_recipients
bcc_address
-
tracking_domain
andsigning_domain
-
merge
,global_merge_vars
andmerge_vars
-
google_analytics_domains
andgoogle_analytics_campaign
-
metadata
andrecipient_metadata
async
ip_pool
send_at
template_name
template_content
Mail.deliver do
delivery_method MultiMail::Sender::Mandrill, :api_key => 'your-api-key',
:async => true, :ip_pool => 'main_pool', ...
...
end
Postmark
Incoming
service = MultiMail::Receiver.new({
:provider => 'postmark',
})
See Postmark's documentation for these additional parameters provided by the API:
MailboxHash
Tag
Outgoing
Mail.deliver do
delivery_method MultiMail::Sender::Postmark, :api_key => 'your-api-key'
to _To_
from _From_
subject _Subject_
text_part do
body _TextBody_
end
html_part do
content_type 'text/html; charset=UTF-8'
body _HtmlBody_
end
end
SendGrid
Incoming
service = MultiMail::Receiver.new({
:provider => 'sendgrid',
})
The default SpamAssassin score needed to flag an email as spam is 5
. Add a :spamassassin_threshold
option to increase or decrease it:
service = MultiMail::Receiver.new({
:provider => 'sendgrid',
:spamassassin_threshold => 4.5,
})
See SendGrid's documentation for these additional parameters provided by the API:
dkim
SPF
spam_report
spam_score
Outgoing
Mail.deliver do
delivery_method MultiMail::Sender::SendGrid, :api_user => 'username', :api_key => 'password'
to _to_
from _from_ + _fromname_
subject _subject_
text_part do
body _text_
end
html_part do
content_type 'text/html; charset=UTF-8'
body _html_
end
end
You may also pass a x-smtpapi
option to delivery_method
(see SendGrid's documentation).
Mail.deliver do
delivery_method MultiMail::Sender::SendGrid, :api_user => 'username', :api_key => 'password',
:x-smtpapi => '{ "some_json" : "with_some_data" }'
...
end
MTA
Incoming
If you are switching from an email API to Postfix or qmail, the simplest option is to continue sending messages to your application's webhook URL.
Your Postfix configuration may look like:
# /etc/postfix/virtual
incoming@myapp.com myappalias
# /etc/mail/aliases
myappalias: "| multi_mail_post --secret my-secret-string http://www.myapp.com/post"
Your qmail configuration may look like:
# /var/qmail/mailnames/myapp.com/.qmail-incoming
| multi_mail_post --secret my-secret-string http://www.myapp.com/post
In your application, you would use the simple
provider:
service = MultiMail::Receiver.new({
:provider => 'simple',
:secret => 'my-secret-string',
})
It's recommended to use a secret key, to ensure that the requests are sent by Postfix and qmail and not by other sources on the internet.
This gem re-uses code from fog, released under the MIT license.
Copyright (c) 2012 James McKinney, released under the MIT license