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.
@@ -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.
@@ -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.
@@ -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
@@ -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
@@ -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,12 @@
1
+ module Incoming
2
+ module Strategies
3
+ class CloudMailin
4
+ include Incoming::Strategy
5
+
6
+ def initialize(request)
7
+ @message = Mail.new(request.params.delete(:message))
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -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: []