XUtils

Incoming

Incoming! helps you receive email in your Rack apps.


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.)

Articles

  • coming soon...