Skip to content

honeybadger-io/incoming

Repository files navigation

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 ⚡ Honeybadger.io, painless Rails exception tracking.

Build Status Gem Version

Installation

  1. Add Incoming! to your Gemfile and run bundle install:

    gem "incoming"
  2. Create a new class to receive emails (see examples below)

  3. 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 whoever@wherever.com with subject "hello world"

Sendgrid API reference

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 whoever@wherever.com with subject "hello world"

Mailgun API reference

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 whoever@wherever.com with subject "hello world"

Postmark API reference

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 whoever@wherever.com with subject "hello world"

CloudMailin API reference

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 whoever@wherever.com with subject "hello world"

Mandrill API reference

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 whoever@wherever.com 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 whoever@wherever.com 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 whoever@example.com 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
    allow(EmailReceiver).to receive(:receive).and_return(true)
    post :create
    expect(response.success?).to eq(true)
    expect(response.body).to eq(%({"status":"ok"}))
  end

  it "responds with 403 when request is invalid" do
    allow(EmailReceiver).to receive(:receive).and_return(false)
    post :create
    expect(response.status).to eq(403)
    expect(response.body).to eq(%({"status":"rejected"}))
  end
end

TODO

  1. Provide authentication for all strategies where possible (currently only Mailgun requests are authenticated.)

Contributing

  1. Fork it.
  2. Create a topic branch git checkout -b my_branch
  3. Commit your changes git commit -am "Boom"
  4. Push to your branch git push origin my_branch
  5. Send a pull request

License

Incoming! is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.