griddler 0.2.0 → 0.3.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/README.md +67 -40
- data/lib/griddler.rb +1 -0
- data/lib/griddler/configuration.rb +3 -11
- data/lib/griddler/email.rb +19 -12
- data/lib/griddler/email_parser.rb +1 -1
- data/lib/griddler/errors.rb +9 -0
- data/lib/griddler/version.rb +1 -1
- metadata +27 -4
data/README.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
|
1
2
|
Griddler
|
2
3
|
========
|
3
4
|
|
5
|
+
### Receive emails in your Rails app
|
6
|
+
|
4
7
|
Griddler is a Rails engine (full plugin) that provides an endpoint for the
|
5
|
-
[Sendgrid parse
|
6
|
-
|
7
|
-
off a built email object to a class implemented by you.
|
8
|
+
[Sendgrid parse api](http://sendgrid.com/docs/API%20Reference/Webhooks/parse.html)
|
9
|
+
that hands off a built email object to a class implemented by you.
|
8
10
|
|
9
11
|
Installation
|
10
12
|
------------
|
@@ -15,10 +17,10 @@ Add griddler to your application's Gemfile and run `bundle install`:
|
|
15
17
|
gem 'griddler'
|
16
18
|
```
|
17
19
|
|
18
|
-
Griddler comes with a default endpoint that will be displayed at the bottom
|
19
|
-
the output of `rake routes`. If there is a previously defined route that
|
20
|
-
`/email_processor`–or you would like to rename the matched path–you
|
21
|
-
add the route to the desired position in routes.rb with the following:
|
20
|
+
Griddler comes with a default endpoint that will be displayed at the bottom
|
21
|
+
of the output of `rake routes`. If there is a previously defined route that
|
22
|
+
matches `/email_processor`–or you would like to rename the matched path–you
|
23
|
+
may add the route to the desired position in routes.rb with the following:
|
22
24
|
|
23
25
|
```ruby
|
24
26
|
match '/email_processor' => 'griddler/emails#create', via: :post
|
@@ -28,70 +30,95 @@ Defaults
|
|
28
30
|
--------
|
29
31
|
|
30
32
|
By default Griddler will look for a class to be created in your application
|
31
|
-
called EmailProcessor with a class method implemented named process, taking
|
32
|
-
one argument (presumably `email`). For example, in `./lib/email_processor.rb`:
|
33
|
+
called EmailProcessor with a class method implemented named process, taking
|
34
|
+
in one argument (presumably `email`). For example, in `./lib/email_processor.rb`:
|
33
35
|
|
34
36
|
```ruby
|
35
37
|
class EmailProcessor
|
36
38
|
def self.process(email)
|
37
|
-
# all of your application-specific code here - creating models,
|
38
|
-
# reports, etc
|
39
|
+
# all of your application-specific code here - creating models,
|
40
|
+
# processing reports, etc
|
39
41
|
end
|
40
42
|
end
|
41
43
|
```
|
42
44
|
|
43
|
-
The contents of the `email` object passed into your process method is
|
44
|
-
|
45
|
+
The contents of the `email` object passed into your process method is an object
|
46
|
+
that responds to:
|
45
47
|
|
46
|
-
*
|
47
|
-
*
|
48
|
-
*
|
49
|
-
*
|
48
|
+
* `.to`
|
49
|
+
* `.from`
|
50
|
+
* `.subject`
|
51
|
+
* `.body`
|
52
|
+
* `.raw_body`
|
50
53
|
|
51
54
|
Each of those has some sensible defaults.
|
52
55
|
|
53
|
-
|
54
|
-
raw from and subject values.
|
56
|
+
`.from`, `.raw_body` and `.subject` will contain the obvious values found in the email, the raw values from those fields.
|
55
57
|
|
56
|
-
|
58
|
+
`.body` will contain the full contents of the email body **unless** there is a
|
57
59
|
line in the email containing the string `-- Reply ABOVE THIS LINE --`. In that
|
58
|
-
case
|
60
|
+
case `.body` will contain everything before that line.
|
59
61
|
|
60
|
-
|
61
|
-
that this is the most often
|
62
|
+
`.to` will contain all of the text before the email's "@" character. We've found
|
63
|
+
that this is the most often used portion of the email address and consider it to
|
62
64
|
be the token we'll key off of for interaction with our application.
|
63
65
|
|
64
66
|
Configuration Options
|
65
67
|
---------------------
|
66
68
|
|
67
|
-
An initializer can be created to control some of the options in Griddler.
|
68
|
-
|
69
|
-
`config/initializer/griddler.rb`:
|
69
|
+
An initializer can be created to control some of the options in Griddler. Defaults
|
70
|
+
are shown below with sample overrides following. In `config/initializer/griddler.rb`:
|
70
71
|
|
71
72
|
```ruby
|
72
73
|
Griddler.configure do |config|
|
73
|
-
config.
|
74
|
-
config.handler_method = :process # :go
|
75
|
-
config.raw_body = false # true
|
74
|
+
config.processor_class = EmailProcessor # MyEmailProcessor
|
76
75
|
config.to = :token # :raw, :email, :hash
|
77
76
|
# :raw => 'AppName <s13.6b2d13dc6a1d33db7644@mail.myapp.com>'
|
78
77
|
# :email => 's13.6b2d13dc6a1d33db7644@mail.myapp.com'
|
79
78
|
# :token => 's13.6b2d13dc6a1d33db7644'
|
80
79
|
# :hash => { raw: '', email: '', token: '', host: '' }
|
81
|
-
config.
|
80
|
+
config.reply_delimiter = '-- REPLY ABOVE THIS LINE --'
|
82
81
|
end
|
83
82
|
```
|
84
83
|
|
85
|
-
* `config.
|
86
|
-
|
87
|
-
* `config.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
84
|
+
* `config.processor_class` change the class Griddler will use to handle your incoming emails.
|
85
|
+
* `config.reply_delimiter` change the string searched for that will split your body.
|
86
|
+
* `config.to` change the format of the returned value for the `:to` key in
|
87
|
+
the email object. `:hash` will return all options within a -- (surprise!) -- hash.
|
88
|
+
|
89
|
+
Testing In Your App
|
90
|
+
-------------------
|
91
|
+
|
92
|
+
You may want to create a factory for when testing the integration of Griddler into
|
93
|
+
your application. If you're using factory_girl this can be accomplished with the
|
94
|
+
following sample factory.
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
factory :email, class: OpenStruct do
|
98
|
+
to 'email-token'
|
99
|
+
from 'user@email.com'
|
100
|
+
subject 'email subject'
|
101
|
+
body 'Hello!'
|
102
|
+
attachments {[]}
|
103
|
+
|
104
|
+
trait :with_attachment do
|
105
|
+
attachments {[
|
106
|
+
ActionDispatch::Http::UploadedFile.new({
|
107
|
+
filename: 'img.png',
|
108
|
+
type: 'image/png',
|
109
|
+
tempfile: File.new("#{File.expand_path File.dirname(__FILE__)}/fixtures/img.png")
|
110
|
+
})
|
111
|
+
]}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
Bear in mind, if you plan on using the :with_attachment trait, that this
|
117
|
+
example assumes your factories are in spec/factories.rb and you have
|
118
|
+
an image file in spec/fixtures/
|
119
|
+
|
120
|
+
To use it in your test(s) just build with `email = build(:email)`
|
121
|
+
or `email = build(:email, :with_attachment)`
|
95
122
|
|
96
123
|
More Information
|
97
124
|
----------------
|
data/lib/griddler.rb
CHANGED
@@ -18,22 +18,14 @@ module Griddler
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class Configuration
|
21
|
-
attr_accessor :
|
21
|
+
attr_accessor :processor_class, :reply_delimiter, :to
|
22
22
|
|
23
23
|
def to
|
24
24
|
@to ||= :token
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
@
|
29
|
-
end
|
30
|
-
|
31
|
-
def handler_method
|
32
|
-
@handler_method ||= :process
|
33
|
-
end
|
34
|
-
|
35
|
-
def raw_body
|
36
|
-
@raw_body ||= false
|
27
|
+
def processor_class
|
28
|
+
@processor_class ||= EmailProcessor
|
37
29
|
end
|
38
30
|
|
39
31
|
def reply_delimiter
|
data/lib/griddler/email.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
-
require '
|
1
|
+
require 'htmlentities'
|
2
2
|
|
3
3
|
class Griddler::Email
|
4
|
-
|
4
|
+
include ActionView::Helpers::SanitizeHelper
|
5
|
+
attr_accessor :to, :from, :body, :raw_body, :subject, :attachments
|
5
6
|
|
6
7
|
def initialize(params)
|
7
8
|
@to = extract_address(params[:to], config.to)
|
8
9
|
@from = extract_address(params[:from], :email)
|
9
10
|
@subject = params[:subject]
|
10
|
-
@body =
|
11
|
+
@body = extract_body(params)
|
12
|
+
@raw_body = params[:text] || params[:html]
|
11
13
|
@attachments = extract_attachments(params)
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
handler_class.send(handler_method, self)
|
15
|
+
processor_class = config.processor_class
|
16
|
+
processor_class.process(self)
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
@@ -41,20 +42,26 @@ class Griddler::Email
|
|
41
42
|
attachment_files
|
42
43
|
end
|
43
44
|
|
44
|
-
def extract_body(
|
45
|
+
def extract_body(params)
|
46
|
+
body_text = text_or_sanitized_html(params)
|
47
|
+
charsets = params[:charsets]
|
48
|
+
|
45
49
|
if charsets.present?
|
46
50
|
charsets = ActiveSupport::JSON.decode(charsets)
|
47
|
-
body_text =
|
51
|
+
body_text = body_text.encode('UTF-8', invalid: :replace,
|
52
|
+
undef: :replace, replace: '').force_encoding('UTF-8')
|
48
53
|
end
|
49
54
|
|
50
55
|
EmailParser.extract_reply_body(body_text)
|
51
56
|
end
|
52
57
|
|
53
|
-
def
|
54
|
-
if
|
55
|
-
|
58
|
+
def text_or_sanitized_html(params)
|
59
|
+
if params.key? :text
|
60
|
+
params[:text]
|
61
|
+
elsif params.key? :html
|
62
|
+
HTMLEntities.new.decode(strip_tags(params[:html]))
|
56
63
|
else
|
57
|
-
|
64
|
+
raise Griddler::Errors::EmailBodyNotFound
|
58
65
|
end
|
59
66
|
end
|
60
67
|
end
|
@@ -26,9 +26,9 @@ module EmailParser
|
|
26
26
|
body.split(delimeter).first.
|
27
27
|
split(/^\s*[-]+\s*Original Message\s*[-]+\s*$/).first.
|
28
28
|
split(/^\s*--\s*$/).first.
|
29
|
+
gsub(/On.*wrote:/, '').
|
29
30
|
split(/[\r]*\n/).reject do |line|
|
30
31
|
line =~ /^\s*>/ ||
|
31
|
-
line =~ /^\s*On.*wrote:$/ ||
|
32
32
|
line =~ /^\s*Sent from my /
|
33
33
|
end.
|
34
34
|
join("\n").
|
data/lib/griddler/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: griddler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2013-01-21 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
- !ruby/object:Gem::Version
|
31
31
|
version: 3.2.0
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
|
-
name:
|
33
|
+
name: htmlentities
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
none: false
|
36
36
|
requirements:
|
37
37
|
- - ! '>='
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0'
|
40
|
-
type: :
|
40
|
+
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
none: false
|
@@ -61,6 +61,22 @@ dependencies:
|
|
61
61
|
- - ! '>='
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: '0'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: sqlite3
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
type: :development
|
73
|
+
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
64
80
|
description:
|
65
81
|
email:
|
66
82
|
- cjaysson@gmail.com
|
@@ -77,6 +93,7 @@ files:
|
|
77
93
|
- lib/griddler/email_format.rb
|
78
94
|
- lib/griddler/email_parser.rb
|
79
95
|
- lib/griddler/engine.rb
|
96
|
+
- lib/griddler/errors.rb
|
80
97
|
- lib/griddler/version.rb
|
81
98
|
- lib/griddler.rb
|
82
99
|
- lib/tasks/griddler_tasks.rake
|
@@ -96,12 +113,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
113
|
- - ! '>='
|
97
114
|
- !ruby/object:Gem::Version
|
98
115
|
version: '0'
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
hash: -3729493469419997719
|
99
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
120
|
none: false
|
101
121
|
requirements:
|
102
122
|
- - ! '>='
|
103
123
|
- !ruby/object:Gem::Version
|
104
124
|
version: '0'
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
hash: -3729493469419997719
|
105
128
|
requirements: []
|
106
129
|
rubyforge_project:
|
107
130
|
rubygems_version: 1.8.24
|