incoming 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []