Incoming!
Receive email in your Rack apps.
Incoming! receives a Rack::Request
and hands you a Mail::Message
, much like ActionMailer::Base.receive
does with a raw email. We currently support the following services:
- SendGrid
- Mailgun
- Postmark
- CloudMailin
- Mandrill
- Any mail server capable of routing messages to a system command
Brought to you by
Installation
Add Incoming! to your Gemfile and run
bundle install
:gem 'incoming'
Create a new class to receive emails (see examples below)
Implement an HTTP endpoint to receive HTTP post hooks, and pass the request to your receiver. (see examples below)
SendGrid example
class EmailReceiver < Incoming::Strategies::SendGrid
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => Got message from [email protected] with subject "hello world"
Mailgun example
class EmailReceiver < Incoming::Strategies::Mailgun
setup :api_key => 'asdf'
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => Got message from [email protected] with subject "hello world"
Postmark example
class EmailReceiver < Incoming::Strategies::Postmark
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => Got message from [email protected] with subject "hello world"
CloudMailin example
Use the Raw Format when setting up your address target.
class EmailReceiver < Incoming::Strategies::CloudMailin
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => Got message from [email protected] with subject "hello world"
Mandrill example
Mandrill is capable of sending multiple events in a single webhook, so the Mandrill strategy works a bit differently than the others. Namely, the .receive
method returns an Array of return values from your #receive
method for each inbound event in the payload. Otherwise, the implementation is the same:
class EmailReceiver < Incoming::Strategies::Mandrill
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => ['Got message from [email protected] with subject "hello world"', '...']
Postfix example
class EmailReceiver < Incoming::Strategies::HTTPPost
setup :secret => '6d7e5337a0cd69f52c3fcf9f5af438b1'
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => Got message from [email protected] with subject "hello world"
# /etc/postfix/virtual
@example.com http_post
# /etc/mail/aliases
http_post: "|http_post -s 6d7e5337a0cd69f52c3fcf9f5af438b1 http://www.example.com/emails"
Qmail example:
class EmailReceiver < Incoming::Strategies::HTTPPost
setup :secret => '6d7e5337a0cd69f52c3fcf9f5af438b1'
def receive(mail)
%(Got message from #{mail.to.first} with subject "#{mail.subject}")
end
end
req = Rack::Request.new(env)
result = EmailReceiver.receive(req) # => Got message from [email protected] with subject "hello world"
To setup a global incoming email alias:
# /var/qmail/alias/.qmail-whoever - mails to whoever@ will be delivered to this alias.
|http_post -s 6d7e5337a0cd69f52c3fcf9f5af438b1 http://www.example.com/emails
Domain-specific incoming aliases can be set as follows:
#/var/qmail/control/virtualdomains
example.com:example
#~example/.qmail-whoever
|http_post -s 6d7e5337a0cd69f52c3fcf9f5af438b1 http://www.example.com/emails
Now mails to [email protected]
will be posted to the corresponding URL above. To post all mails for example.com
, just add the above line to ~example/.qmail-default
.
Example Rails controller
# app/controllers/emails_controller.rb
class EmailsController < ActionController::Base
def create
if EmailReceiver.receive(request)
render :json => { :status => 'ok' }
else
render :json => { :status => 'rejected' }, :status => 403
end
end
end
# config/routes.rb
Rails.application.routes.draw do
post '/emails' => 'emails#create'
end
# spec/controllers/emails_controller_spec.rb
require 'spec_helper'
describe EmailsController, '#create' do
it 'responds with success when request is valid' do
EmailReceiver.should_receive(:receive).and_return(true)
post :create
response.should be_success
response.body.should eq '{"status":"ok"}'
end
it 'responds with 403 when request is invalid' do
EmailReceiver.should_receive(:receive).and_return(false)
post :create
response.status.should eq 403
response.body.should eq '{"status":"rejected"}'
end
end
TODO
- Provide authentication for all strategies where possible (currently only Mailgun requests are authenticated.)
Contributing
- Fork it.
- Create a topic branch
git checkout -b my_branch
- Commit your changes
git commit -am "Boom"
- Push to your branch
git push origin my_branch
- Send a pull request
License
Incoming! is Copyright 2013 © Joshua Wood and Honeybadger Industries LLC. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.