airmail 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c9710202c8bf57ba445332b14803f9f87149ffb4
4
+ data.tar.gz: 59baa6d1b4bc05dc2742c815c943b2a5ab161ce4
5
+ SHA512:
6
+ metadata.gz: a780b078507aa04f219dde6e1a28fc76bfbbd6ca1a6d2478c6826e5a400dc1b49336c0d7d7d74f6cf1f4f009f61bc10071324a44888da5e66b31a74a86ab75e0
7
+ data.tar.gz: 75f69ff448caa3d4117d2c6bcd747847f4c9976f31b757defc9d74af57cb0dafa53b08ef9112d55193166cdecdea6621d080c2d835a06e1b73191596f764ff4e
@@ -0,0 +1,30 @@
1
+ require 'mail'
2
+
3
+ module Airmail
4
+ class << self
5
+ def receive( original )
6
+ raise RoutesNotDefined unless defined? @@route
7
+
8
+ mail = Mail.new( original )
9
+ MailProcessor.new(mail, @@route).receive
10
+
11
+ mail
12
+ end
13
+
14
+ def route(&route)
15
+ @@route = route
16
+ end
17
+
18
+ def logger= logr
19
+ @@logger = logr
20
+ end
21
+
22
+ def logger
23
+ defined?(@@logger) ? @@logger : Logger.new("log/airmail.log")
24
+ end
25
+
26
+ end
27
+ end
28
+
29
+ class RoutesNotDefined < StandardError
30
+ end
@@ -0,0 +1,4 @@
1
+ class AirmailDefaultController < Airmail::Controller
2
+ def receive
3
+ end
4
+ end
@@ -0,0 +1,43 @@
1
+ module Airmail
2
+ class Controller
3
+ def initialize(mail)
4
+ @mail = mail
5
+ end
6
+
7
+ def from
8
+ return @from if @from
9
+
10
+ @from = if @mail.from.is_a? Array
11
+ @mail.from.first
12
+ else
13
+ @mail.from
14
+ end
15
+ end
16
+
17
+ def to
18
+ @to ||= Array.wrap(@mail.to) + Array.wrap(@mail.cc)
19
+ end
20
+
21
+ def subject
22
+ @mail.subject
23
+ end
24
+
25
+ def headers
26
+ @mail.header
27
+ end
28
+
29
+ def reference_id
30
+ reference_id = headers['Reference-ID'].is_a?(Array) && headers['Reference-ID'].last.value
31
+ reference_id ||= headers['Reference-ID'] && headers['Reference-ID'].value
32
+ reference_id ||= headers['References'] && headers['References'].value
33
+
34
+ reference_id = headers['Message-ID'] if reference_id.blank?
35
+ reference_id
36
+ end
37
+
38
+ def attachments
39
+ @mail.attachments
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ class MailProcessor
2
+
3
+ def initialize mail, route
4
+ @mail = mail
5
+ @route = route
6
+ default_controller
7
+ end
8
+
9
+ def receive
10
+ default_controller
11
+ self.instance_eval(&@route)
12
+
13
+ @delivering_controller ||= AirmailDefaultController
14
+ @delivering_controller.new(@mail).receive
15
+ end
16
+
17
+ def from? *args
18
+ from
19
+ end
20
+
21
+ def has_attachment?
22
+ @mail.attachments.size > 0
23
+ end
24
+
25
+ def deliver controller
26
+ @delivering_controller ||= controller
27
+ end
28
+
29
+ def deliver_to controller
30
+ controller = controller.gsub(/(^|_)([a-z])/){ $2.upcase }
31
+ @delivering_controller ||= "#{controller}Controller".constantize
32
+ end
33
+
34
+ def default_controller
35
+ @delivering_controller = nil
36
+ end
37
+
38
+ def logger
39
+ Airmail.logger
40
+ end
41
+
42
+ end
@@ -0,0 +1,74 @@
1
+ require 'mail'
2
+ class MailRouter
3
+
4
+ def initialize(mail)
5
+ @mail = mail
6
+ end
7
+
8
+ def route #this is the app specific controller logic
9
+ MailRouter.info("Receiving email '#{@mail.subject}' from #{@mail.from}, #{@mail.to} with #{@mail.attachments.count} attachments")
10
+
11
+ @mail.attachments.each do |attach|
12
+ MailRouter.info(">> #{attach.filename}")#(#{a.content_type.to_s})")
13
+ end
14
+
15
+ #TODO catch mailerdaemon stuff
16
+ #TODO circular loops? throttle speed
17
+ #if from? :mailerdaemon, :root
18
+
19
+ (deliver MailDemoController and return) if @mail.to.join(" ") =~ /demo.*@amendment.io/
20
+
21
+ if has_attachment?
22
+ #if not on the contact list, don't grant access to services
23
+ (deliver ThanksForPlayingController and return) unless Contact.find_by_email(@mail.from.collect{|f| f.downcase})
24
+
25
+ (deliver AttachmentController and return)
26
+ end
27
+
28
+ deliver DefaultController and return
29
+ end
30
+
31
+ def from? *args
32
+ from
33
+ end
34
+
35
+ def has_attachment?
36
+ @mail.attachments.size > 0
37
+ end
38
+
39
+ def deliver controller
40
+ controller.new(@mail).receive
41
+ end
42
+
43
+ class << self
44
+
45
+ def receive( original )
46
+ mail = Mail.new( original )
47
+
48
+ record(mail, original)
49
+ self.new(mail).route
50
+
51
+ mail
52
+ end
53
+
54
+ def record(mail, original)
55
+ Message.create!(
56
+ from: mail.from.first,
57
+ #reference_id: mail.
58
+ to: mail.to,
59
+ subject: mail.subject,
60
+ original: original,
61
+ taxonomy: 'log'
62
+ )
63
+ end
64
+
65
+ def info msg
66
+ @logger && @logger.info(msg)
67
+ end
68
+
69
+ def logger= loggr
70
+ @logger = loggr
71
+ end
72
+
73
+ end
74
+ end
data/lib/airmail.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'airmail/mail_router'
2
+ require 'airmail/mail_processor'
3
+
4
+ require 'airmail/mail_controller'
5
+ require 'airmail/airmail_default_controller'
6
+ require 'airmail/airmail' #tmp
7
+
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe Airmail do
4
+
5
+ let(:mail) { :garbage }
6
+
7
+ it 'sets route' do
8
+ Airmail.route do
9
+ Counter.inc
10
+ end
11
+
12
+ expect(Airmail.class_variable_get(:@@route)).to be_a(Proc)
13
+ end
14
+
15
+ context 'received email' do
16
+
17
+ before :each do
18
+ Counter.reset
19
+
20
+ Airmail.route do
21
+ Counter.inc
22
+ end
23
+
24
+ Airmail.receive(mail)
25
+ end
26
+
27
+ it 'runs route' do
28
+ expect(Counter.count).to eq(1)
29
+ end
30
+
31
+ it 'runs route for each mail' do
32
+ Airmail.receive(mail)
33
+ expect(Counter.count).to eq(2)
34
+ end
35
+
36
+ end
37
+
38
+ context 'multiple controllers' do
39
+
40
+ it 'delivers once' do
41
+ Counter.reset
42
+
43
+ Airmail.route do
44
+ deliver CountController
45
+ deliver CountController
46
+ end
47
+
48
+ Airmail.receive(mail)
49
+ expect(Counter.count).to eq(1)
50
+ end
51
+
52
+ it 'delivers to the first controller' do
53
+ Counter.reset
54
+
55
+ Airmail.route do
56
+ deliver BlankController
57
+ deliver CountController
58
+ end
59
+
60
+ Airmail.receive(mail)
61
+ expect(Counter.count).to eq(0)
62
+ end
63
+
64
+ it 'delivers to the first controller' do
65
+ Counter.reset
66
+
67
+ Airmail.route do
68
+ deliver CountController
69
+ deliver BlankController
70
+ end
71
+
72
+ Airmail.receive(mail)
73
+ expect(Counter.count).to eq(1)
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
80
+ class CountController < Airmail::Controller
81
+ def receive
82
+ Counter.inc
83
+ end
84
+ end
85
+
86
+ class BlankController < Airmail::Controller
87
+ def receive
88
+ end
89
+ end
90
+
91
+ class Counter
92
+ @@val = 0
93
+
94
+ def self.reset
95
+ @@val = 0
96
+ end
97
+
98
+ def self.inc
99
+ @@val += 1
100
+ end
101
+
102
+ def self.count
103
+ @@val
104
+ end
105
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../../lib/airmail', __FILE__)
2
+
3
+ RSpec.configure do |config|
4
+ config.expect_with :rspec do |expectations|
5
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
6
+ end
7
+
8
+ # rspec-mocks config goes here. You can use an alternate test double
9
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
10
+
11
+ config.mock_with :rspec do |mocks|
12
+ # Prevents you from mocking or stubbing a method that does not exist on
13
+ # a real object. This is generally recommended, and will default to
14
+ # `true` in RSpec 4.
15
+ mocks.verify_partial_doubles = true
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: airmail
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Trevor Grayson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mail
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
41
+ description: Ruby on Wings!
42
+ email: trevor@trevorgrayson.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/airmail.rb
48
+ - lib/airmail/airmail.rb
49
+ - lib/airmail/airmail_default_controller.rb
50
+ - lib/airmail/mail_controller.rb
51
+ - lib/airmail/mail_processor.rb
52
+ - lib/airmail/mail_router.rb
53
+ - spec/airmail_spec.rb
54
+ - spec/spec_helper.rb
55
+ homepage: https://rubygems.org/gems/airmail
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 2.4.5.1
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Incoming Email Router
79
+ test_files: []