incoming 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +22 -0
- data/README.md +138 -0
- data/Rakefile +97 -0
- data/bin/http_post +43 -0
- data/lib/incoming.rb +14 -0
- data/lib/incoming/strategies/cloudmailin.rb +12 -0
- data/lib/incoming/strategies/http_post.rb +25 -0
- data/lib/incoming/strategies/mailgun.rb +72 -0
- data/lib/incoming/strategies/postmark.rb +35 -0
- data/lib/incoming/strategies/sendgrid.rb +34 -0
- data/lib/incoming/strategy.rb +106 -0
- metadata +157 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013, Honeybadger Industries LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
Incoming!
|
2
|
+
-----------
|
3
|
+
|
4
|
+
Incoming! helps you receive email in your Rack apps.
|
5
|
+
|
6
|
+
Brought to you by :zap: **Honeybadger.io**, painless [Rails exception tracking](https://www.honeybadger.io/).
|
7
|
+
|
8
|
+
## Sendgrid example:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
class EmailReceiver < Incoming::Strategies::Sendgrid
|
12
|
+
def receive(mail)
|
13
|
+
puts %(Got message from #{mail.to.first} with subject "#{mail.subject}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
req = Rack::Request.new(env)
|
18
|
+
result = EmailReceiver.receive(req) # => Got message from whoever@wherever.com with subject "hello world"
|
19
|
+
```
|
20
|
+
|
21
|
+
## Mailgun example:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class EmailReceiver < Incoming::Strategies::Mailgun
|
25
|
+
setup :api_key => 'asdf'
|
26
|
+
|
27
|
+
def receive(mail)
|
28
|
+
puts %(Got message from #{mail.to.first} with subject "#{mail.subject}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
req = Rack::Request.new(env)
|
33
|
+
result = EmailReceiver.receive(req) # => Got message from whoever@wherever.com with subject "hello world"
|
34
|
+
```
|
35
|
+
|
36
|
+
## Postmark example:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class EmailReceiver < Incoming::Strategies::Postmark
|
40
|
+
def receive(mail)
|
41
|
+
puts %(Got message from #{mail.to.first} with subject "#{mail.subject}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
req = Rack::Request.new(env)
|
46
|
+
result = EmailReceiver.receive(req) # => Got message from whoever@wherever.com with subject "hello world"
|
47
|
+
```
|
48
|
+
|
49
|
+
## CloudMailin example:
|
50
|
+
|
51
|
+
Use the Raw Format when setting up your address target.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class EmailReceiver < Incoming::Strategies::CloudMailin
|
55
|
+
def receive(mail)
|
56
|
+
puts %(Got message from #{mail.to.first} with subject "#{mail.subject}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
req = Rack::Request.new(env)
|
61
|
+
result = EmailReceiver.receive(req) # => Got message from whoever@wherever.com with subject "hello world"
|
62
|
+
```
|
63
|
+
|
64
|
+
## Postfix example:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
class EmailReceiver < Incoming::Strategies::HTTPPost
|
68
|
+
setup :secret => '6d7e5337a0cd69f52c3fcf9f5af438b1'
|
69
|
+
|
70
|
+
def receive(mail)
|
71
|
+
puts %(Got message from #{mail.to.first} with subject "#{mail.subject}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
req = Rack::Request.new(env)
|
76
|
+
result = EmailReceiver.receive(req) # => Got message from whoever@wherever.com with subject "hello world"
|
77
|
+
```
|
78
|
+
|
79
|
+
```
|
80
|
+
# Postfix virtual alias
|
81
|
+
http_post: "|http_post -s 6d7e5337a0cd69f52c3fcf9f5af438b1 http://www.example.com/emails"
|
82
|
+
```
|
83
|
+
|
84
|
+
## Example Rails controller
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
# app/controllers/emails_controller.rb
|
88
|
+
class EmailsController < ActionController::Base
|
89
|
+
def create
|
90
|
+
if EmailReceiver.receive(request)
|
91
|
+
render :json => { :status => 'ok' }
|
92
|
+
else
|
93
|
+
render :json => { :status => 'rejected' }, :status => 403
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# config/routes.rb
|
101
|
+
Rails.application.routes.draw do
|
102
|
+
post '/emails' => 'emails#create'
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
# spec/controllers/emails_controller_spec.rb
|
108
|
+
require 'spec_helper'
|
109
|
+
|
110
|
+
describe EmailsController, '#create' do
|
111
|
+
it 'responds with success when request is valid' do
|
112
|
+
EmailReceiver.should_receive(:receive).and_return(true)
|
113
|
+
post :create
|
114
|
+
response.should be_success
|
115
|
+
response.body.should eq '{"status":"ok"}'
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'responds with 403 when request is invalid' do
|
119
|
+
EmailReceiver.should_receive(:receive).and_return(false)
|
120
|
+
post :create
|
121
|
+
response.status.should eq 403
|
122
|
+
response.body.should eq '{"status":"rejected"}'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
## Contributing
|
128
|
+
|
129
|
+
1. Fork it.
|
130
|
+
2. Create a topic branch `git checkout -b my_branch`
|
131
|
+
3. Commit your changes `git commit -am "Boom"`
|
132
|
+
3. Push to your branch `git push origin my_branch`
|
133
|
+
4. Send a [pull request](https://github.com/honeybadger-io/incoming/pulls)
|
134
|
+
|
135
|
+
## License
|
136
|
+
|
137
|
+
Incoming! is Copyright 2013 © Honeybadger Industries LLC. It is free software, and
|
138
|
+
may be redistributed under the terms specified in the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'date'
|
9
|
+
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
task :default => :spec
|
13
|
+
|
14
|
+
#############################################################################
|
15
|
+
#
|
16
|
+
# Helper functions
|
17
|
+
#
|
18
|
+
#############################################################################
|
19
|
+
|
20
|
+
def name
|
21
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
22
|
+
end
|
23
|
+
|
24
|
+
def version
|
25
|
+
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
26
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
27
|
+
end
|
28
|
+
|
29
|
+
def date
|
30
|
+
Date.today.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def gemspec_file
|
34
|
+
"#{name}.gemspec"
|
35
|
+
end
|
36
|
+
|
37
|
+
def gem_file
|
38
|
+
"#{name}-#{version}.gem"
|
39
|
+
end
|
40
|
+
|
41
|
+
def replace_header(head, header_name)
|
42
|
+
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
43
|
+
end
|
44
|
+
|
45
|
+
#############################################################################
|
46
|
+
#
|
47
|
+
# Packaging tasks
|
48
|
+
#
|
49
|
+
#############################################################################
|
50
|
+
|
51
|
+
desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
|
52
|
+
task :release => :build do
|
53
|
+
unless `git branch` =~ /^\* master$/
|
54
|
+
puts "You must be on the master branch to release!"
|
55
|
+
exit!
|
56
|
+
end
|
57
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
58
|
+
sh "git tag v#{version}"
|
59
|
+
sh "git push origin master"
|
60
|
+
sh "git push origin v#{version}"
|
61
|
+
sh "gem push pkg/#{name}-#{version}.gem"
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "Build #{gem_file} into the pkg directory"
|
65
|
+
task :build => :gemspec do
|
66
|
+
sh "mkdir -p pkg"
|
67
|
+
sh "gem build #{gemspec_file}"
|
68
|
+
sh "mv #{gem_file} pkg"
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "Generate #{gemspec_file}"
|
72
|
+
task :gemspec => :validate do
|
73
|
+
# read spec file and split out manifest section
|
74
|
+
spec = File.read(gemspec_file)
|
75
|
+
|
76
|
+
# replace name version and date
|
77
|
+
replace_header(spec, :name)
|
78
|
+
replace_header(spec, :version)
|
79
|
+
replace_header(spec, :date)
|
80
|
+
|
81
|
+
# piece file back together and write
|
82
|
+
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
83
|
+
puts "Updated #{gemspec_file}"
|
84
|
+
end
|
85
|
+
|
86
|
+
desc "Validate #{gemspec_file}"
|
87
|
+
task :validate do
|
88
|
+
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}", "lib/tasks", "lib/generators"]
|
89
|
+
unless libfiles.empty?
|
90
|
+
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
91
|
+
exit!
|
92
|
+
end
|
93
|
+
unless Dir['VERSION*'].empty?
|
94
|
+
puts "A `VERSION` file at root level violates Gem best practices."
|
95
|
+
exit!
|
96
|
+
end
|
97
|
+
end
|
data/bin/http_post
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'incoming'
|
4
|
+
require 'net/http'
|
5
|
+
require 'uri'
|
6
|
+
require 'openssl'
|
7
|
+
require 'securerandom'
|
8
|
+
require 'optparse'
|
9
|
+
|
10
|
+
options = {
|
11
|
+
secret: nil
|
12
|
+
}
|
13
|
+
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: http_post [options] [http endpoint] < input"
|
16
|
+
opts.on('-s', '--secret [secret]') { |s| options[:secret] = s }
|
17
|
+
|
18
|
+
opts.parse!
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
http_endpoint = URI.parse(ARGV[0])
|
23
|
+
rescue URI::InvalidURIError
|
24
|
+
puts 'Unable to parse http endpoint. Is it a valid URI?'
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
timestamp = Time.now.to_i
|
29
|
+
token = SecureRandom.hash
|
30
|
+
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA256'), options[:secret], [timestamp, token].join)
|
31
|
+
|
32
|
+
data = { :message => STDIN.read, :timestamp => timestamp, :token => token, :signature => signature }
|
33
|
+
headers = {}
|
34
|
+
|
35
|
+
req = Net::HTTP::Post.new(http_endpoint.path, headers)
|
36
|
+
req.form_data = data
|
37
|
+
req.basic_auth http_endpoint.user, http_endpoint.password if http_endpoint.user
|
38
|
+
|
39
|
+
resp, data = Net::HTTP.new(http_endpoint.host, http_endpoint.port).start {|http|
|
40
|
+
http.request(req)
|
41
|
+
}
|
42
|
+
|
43
|
+
puts resp.body
|
data/lib/incoming.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'mail'
|
2
|
+
require 'incoming/strategy'
|
3
|
+
|
4
|
+
module Incoming
|
5
|
+
VERSION = '0.1.0'
|
6
|
+
|
7
|
+
module Strategies
|
8
|
+
autoload :Sendgrid, 'incoming/strategies/sendgrid'
|
9
|
+
autoload :Mailgun, 'incoming/strategies/mailgun'
|
10
|
+
autoload :Postmark, 'incoming/strategies/postmark'
|
11
|
+
autoload :CloudMailin, 'incoming/strategies/cloudmailin'
|
12
|
+
autoload :HTTPPost, 'incoming/strategies/http_post'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Incoming
|
2
|
+
module Strategies
|
3
|
+
class HTTPPost
|
4
|
+
include Incoming::Strategy
|
5
|
+
|
6
|
+
option :secret
|
7
|
+
|
8
|
+
attr_accessor :signature, :token, :timestamp
|
9
|
+
|
10
|
+
def initialize(request)
|
11
|
+
params = request.params
|
12
|
+
|
13
|
+
@signature = params.delete(:signature)
|
14
|
+
@token = params.delete(:token)
|
15
|
+
@timestamp = params.delete(:timestamp)
|
16
|
+
@message = Mail.new(params.delete(:message))
|
17
|
+
end
|
18
|
+
|
19
|
+
def authenticate
|
20
|
+
hexdigest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA256'), self.class.default_options[:secret], [timestamp, token].join)
|
21
|
+
hexdigest.eql?(signature) or false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Incoming
|
4
|
+
module Strategies
|
5
|
+
# Public: MailGun Incoming! Mail Strategy
|
6
|
+
#
|
7
|
+
# API Documentation:
|
8
|
+
# http://documentation.mailgun.net/user_manual.html#receiving-messages
|
9
|
+
#
|
10
|
+
# Examples:
|
11
|
+
#
|
12
|
+
# class MailReceiver < Incoming::Strategies::Mailgun
|
13
|
+
# setup api_key: 'asdf'
|
14
|
+
#
|
15
|
+
# def receive(mail)
|
16
|
+
# puts "Got message from mailgun: #{mail.subject}"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
class Mailgun
|
20
|
+
include Incoming::Strategy
|
21
|
+
|
22
|
+
# Mailgun API key
|
23
|
+
option :api_key
|
24
|
+
|
25
|
+
# Use the stripped- parameters from the Mailgun API (strips out quoted parts and signatures)
|
26
|
+
option :stripped, false
|
27
|
+
|
28
|
+
attr_accessor :signature, :token, :timestamp
|
29
|
+
|
30
|
+
def initialize(request)
|
31
|
+
params = request.params
|
32
|
+
|
33
|
+
if self.class.default_options[:api_key].nil?
|
34
|
+
raise RequiredOptionError.new(':api_key option is required.')
|
35
|
+
end
|
36
|
+
|
37
|
+
@signature = params['signature']
|
38
|
+
@token = params['token']
|
39
|
+
@timestamp = params['timestamp']
|
40
|
+
|
41
|
+
html_content = params[ self.class.default_options[:stripped] ? 'stripped-html' : 'body-html' ]
|
42
|
+
text_content = params[ self.class.default_options[:stripped] ? 'stripped-text' : 'body-plain' ]
|
43
|
+
|
44
|
+
@message = Mail.new do
|
45
|
+
headers Hash[JSON.parse(params['message-headers'])]
|
46
|
+
from params['from']
|
47
|
+
to params['recipient']
|
48
|
+
subject params['subject']
|
49
|
+
|
50
|
+
body text_content
|
51
|
+
|
52
|
+
html_part do
|
53
|
+
content_type 'text/html; charset=UTF-8'
|
54
|
+
body html_content
|
55
|
+
end if html_content
|
56
|
+
|
57
|
+
1.upto(params['attachment-count'].to_i).each do |num|
|
58
|
+
attachment = params["attachment-#{num}"]
|
59
|
+
add_file(:filename => attachment.original_filename, :content => attachment.read)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def authenticate
|
65
|
+
api_key = self.class.default_options[:api_key]
|
66
|
+
|
67
|
+
hexdigest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA256'), api_key, [timestamp, token].join)
|
68
|
+
hexdigest.eql?(signature) or false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'postmark_mitt'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Incoming
|
5
|
+
module Strategies
|
6
|
+
class Postmark
|
7
|
+
include Incoming::Strategy
|
8
|
+
|
9
|
+
def initialize(request)
|
10
|
+
email = ::Postmark::Mitt.new(request.body.read)
|
11
|
+
|
12
|
+
@attachments = email.attachments
|
13
|
+
|
14
|
+
@message = Mail.new do
|
15
|
+
headers email.headers
|
16
|
+
from email.from
|
17
|
+
to email.to
|
18
|
+
reply_to email.reply_to
|
19
|
+
subject email.subject
|
20
|
+
|
21
|
+
body email.text_body
|
22
|
+
|
23
|
+
html_part do
|
24
|
+
content_type 'text/html; charset=UTF-8'
|
25
|
+
body email.html_body
|
26
|
+
end if email.html_body
|
27
|
+
|
28
|
+
email.attachments.each do |a|
|
29
|
+
add_file :filename => a.file_name, :content => Base64.decode64(a.source['Content'])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Incoming
|
2
|
+
module Strategies
|
3
|
+
class Sendgrid
|
4
|
+
include Incoming::Strategy
|
5
|
+
|
6
|
+
def initialize(request)
|
7
|
+
params = request.params.dup
|
8
|
+
envelope = JSON.parse(params['envelope'])
|
9
|
+
|
10
|
+
# TODO: Properly handle encodings
|
11
|
+
# encodings = JSON.parse(params['charsets'])
|
12
|
+
|
13
|
+
@message = Mail.new do
|
14
|
+
header params['headers']
|
15
|
+
from params['from']
|
16
|
+
to envelope['to'].first
|
17
|
+
subject params['subject']
|
18
|
+
|
19
|
+
body params['text']
|
20
|
+
|
21
|
+
html_part do
|
22
|
+
content_type 'text/html; charset=UTF-8'
|
23
|
+
body params['html']
|
24
|
+
end if params['html']
|
25
|
+
|
26
|
+
1.upto(params['attachments'].to_i).each do |num|
|
27
|
+
attachment = params["attachment#{num}"]
|
28
|
+
add_file(:filename => attachment.original_filename, :content => attachment.read)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Incoming
|
2
|
+
module Strategy
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.class_eval do
|
6
|
+
attr_reader :options
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class RequiredOptionError < StandardError ; end
|
11
|
+
class InvalidOptionError < StandardError ; end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Public: Global receiver
|
15
|
+
#
|
16
|
+
# args - Arguments used to initialize strategy. Should be defined
|
17
|
+
# by `initialize` method in strategy class.
|
18
|
+
#
|
19
|
+
# Returns nothing
|
20
|
+
def receive(*args)
|
21
|
+
strategy = new(*args)
|
22
|
+
strategy.authenticate and strategy.receive(strategy.message)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public
|
26
|
+
# Returns an inherited set of default options set at the class-level
|
27
|
+
# for each strategy.
|
28
|
+
def default_options
|
29
|
+
return @default_options if @default_options
|
30
|
+
@default_options = superclass.respond_to?(:default_options) ? superclass.default_options : {}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Public: Defines a valid class-level option for strategy
|
34
|
+
#
|
35
|
+
# Examples:
|
36
|
+
#
|
37
|
+
# class Incoming::Strategies::MyStrategy
|
38
|
+
# include Incoming::Strategy
|
39
|
+
# option :api_key
|
40
|
+
# option :mime, false
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# Returns nothing
|
44
|
+
def option(name, value = nil)
|
45
|
+
default_options[name] = value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Configures strategy-specific options.
|
49
|
+
#
|
50
|
+
# opts - A hash of valid options.
|
51
|
+
#
|
52
|
+
# Examples:
|
53
|
+
#
|
54
|
+
# class MailReceiver < Incoming::Strategies::MyStrategy
|
55
|
+
# setup api_key: 'asdf', mime: true
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# Returns nothing
|
59
|
+
def setup(opts = {})
|
60
|
+
opts.keys.each do |key|
|
61
|
+
next if default_options.keys.include?(key)
|
62
|
+
raise InvalidOptionError.new(":#{key} is not a valid option for #{self.superclass.name}.")
|
63
|
+
end
|
64
|
+
|
65
|
+
@default_options = default_options.merge(opts)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Public: A Mail::Message object, constructed by #initialize
|
70
|
+
attr_accessor :message
|
71
|
+
|
72
|
+
# Public: Translates arguments into a Mail::Message object
|
73
|
+
def initialize(*args) ; end
|
74
|
+
|
75
|
+
protected
|
76
|
+
|
77
|
+
# Protected: Evaluates message and performs appropriate action.
|
78
|
+
# Override in subclass
|
79
|
+
#
|
80
|
+
# mail - A Mail::Message object
|
81
|
+
#
|
82
|
+
# Returns nothing
|
83
|
+
def receive(mail)
|
84
|
+
raise NotImplementedError.new('You must implement #receive')
|
85
|
+
end
|
86
|
+
|
87
|
+
# Protected: Authenticates request before performing #receive
|
88
|
+
#
|
89
|
+
# Examples:
|
90
|
+
#
|
91
|
+
# class MailReceiver < Incoming::Strategies::MyStrategy
|
92
|
+
# def initialize(request)
|
93
|
+
# @secret_word = request.params['secret_word']
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# def protected
|
97
|
+
# @secret_word == 'my secret word'
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# Returns true by default
|
102
|
+
def authenticate
|
103
|
+
true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: incoming
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joshua Wood
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mail
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.4.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.4.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: postmark-mitt
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.0.11
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.0.11
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: guard-rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Incoming! standardizes various mail parse apis, making it a snap to receive
|
111
|
+
emails through HTTP post hooks.
|
112
|
+
email:
|
113
|
+
- josh@honeybadger.io
|
114
|
+
executables:
|
115
|
+
- http_post
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- lib/incoming/strategies/cloudmailin.rb
|
120
|
+
- lib/incoming/strategies/http_post.rb
|
121
|
+
- lib/incoming/strategies/mailgun.rb
|
122
|
+
- lib/incoming/strategies/postmark.rb
|
123
|
+
- lib/incoming/strategies/sendgrid.rb
|
124
|
+
- lib/incoming/strategy.rb
|
125
|
+
- lib/incoming.rb
|
126
|
+
- MIT-LICENSE
|
127
|
+
- Rakefile
|
128
|
+
- README.md
|
129
|
+
- bin/http_post
|
130
|
+
homepage: https://www.honeybadger.io/
|
131
|
+
licenses: []
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
hash: -2639697308401258513
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: 1.8.25
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 1.8.25
|
154
|
+
signing_key:
|
155
|
+
specification_version: 3
|
156
|
+
summary: Incoming! helps you receive email in your Rack apps.
|
157
|
+
test_files: []
|