griddler 0.6.1 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -13
- data/lib/griddler.rb +1 -0
- data/lib/griddler/adapters/cloudmailin_adapter.rb +5 -0
- data/lib/griddler/adapters/mailgun_adapter.rb +57 -0
- data/lib/griddler/adapters/mandrill_adapter.rb +7 -1
- data/lib/griddler/adapters/postmark_adapter.rb +4 -3
- data/lib/griddler/adapters/sendgrid_adapter.rb +4 -3
- data/lib/griddler/configuration.rb +10 -1
- data/lib/griddler/email.rb +24 -25
- data/lib/griddler/email_parser.rb +4 -2
- data/lib/griddler/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c93ac0eaccf2bf366151a3d202d31fb80c955e3a
|
4
|
+
data.tar.gz: 7966242ad3ac5d8566b8ed991b3b1118f266d88d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42e335e21700230465f2f60b9148cb0bd7188c5b99c86421d8bb06d3e34f8c4658a0b871c1248d5620a1edf4b1cb59e200bc961b0df5571c0698eda403894fc6
|
7
|
+
data.tar.gz: 40fdce0ad4cdd2e3644b40a253bf427e1b724c70831c36ae02ddd07b4efc07b835fda1e48537d7cca073f2d5d08a105d7a4c23144e870fb5e33ad10f5ce32af0
|
data/README.md
CHANGED
@@ -11,6 +11,7 @@ Griddler is a Rails engine (full plugin) that provides an endpoint for the
|
|
11
11
|
[Cloudmailin parse api](http://cloudmailin.com),
|
12
12
|
[Postmark parse api](http://developer.postmarkapp.com/developer-inbound-parse.html) or
|
13
13
|
[Mandrill parse api](http://help.mandrill.com/entries/21699367-Inbound-Email-Processing-Overview)
|
14
|
+
[Mailgun routes](http://documentation.mailgun.com/user_manual.html#receiving-messages-via-http-through-a-forward-action)
|
14
15
|
that hands off a built email object to a class implemented by you.
|
15
16
|
|
16
17
|
Tutorials
|
@@ -30,9 +31,18 @@ Add griddler to your application's Gemfile and run `bundle install`:
|
|
30
31
|
```ruby
|
31
32
|
gem 'griddler'
|
32
33
|
```
|
34
|
+
A route is needed for the endpoint which receives `POST` messages. Currently,
|
35
|
+
the route is automatically appended to the route table like so:
|
33
36
|
|
34
|
-
|
35
|
-
|
37
|
+
```ruby
|
38
|
+
email_processor POST /email_processor(.:format) griddler/emails#create
|
39
|
+
```
|
40
|
+
|
41
|
+
**NOTE: This behavior is deprecated and will be removed by version 0.7.0 in favor
|
42
|
+
of manually adding the route.**
|
43
|
+
|
44
|
+
To manually add the route, in `config/routes.rb` you may either use the provided
|
45
|
+
routing method `mount_griddler` or set the route explicitly. Examples:
|
36
46
|
|
37
47
|
```ruby
|
38
48
|
# mount using default path
|
@@ -45,11 +55,6 @@ mount_griddler('/email/incoming')
|
|
45
55
|
post '/email_processor' => 'griddler/emails#create'
|
46
56
|
```
|
47
57
|
|
48
|
-
**NOTE:** Currently the default route is added to the bottom of your route table.
|
49
|
-
By version 0.7.0 it will be removed and you will be required to add the route
|
50
|
-
with one of the three above methods.
|
51
|
-
|
52
|
-
|
53
58
|
Defaults
|
54
59
|
--------
|
55
60
|
|
@@ -71,6 +76,7 @@ that responds to:
|
|
71
76
|
|
72
77
|
* `.to`
|
73
78
|
* `.from`
|
79
|
+
* `.cc`
|
74
80
|
* `.subject`
|
75
81
|
* `.body`
|
76
82
|
* `.raw_text`
|
@@ -108,6 +114,9 @@ information of each recipient:
|
|
108
114
|
`.from` will default to the `email` value of a hash like `.to`, and can be
|
109
115
|
configured to return the full hash.
|
110
116
|
|
117
|
+
`.cc` behaves and can be configured like `.to`. If the adapter does not
|
118
|
+
pass along a `cc` key then the headers will be parsed.
|
119
|
+
|
111
120
|
`.attachments` will contain an array of attachments as multipart/form-data files
|
112
121
|
which can be passed off to attachment libraries like Carrierwave or Paperclip.
|
113
122
|
|
@@ -118,26 +127,28 @@ Configuration Options
|
|
118
127
|
---------------------
|
119
128
|
|
120
129
|
An initializer can be created to control some of the options in Griddler. Defaults
|
121
|
-
are shown below with sample overrides following. In `config/
|
130
|
+
are shown below with sample overrides following. In `config/initializers/griddler.rb`:
|
122
131
|
|
123
132
|
```ruby
|
124
133
|
Griddler.configure do |config|
|
125
134
|
config.processor_class = EmailProcessor # MyEmailProcessor
|
135
|
+
config.processor_method = :process # :custom_method
|
126
136
|
config.to = :hash # :full, :email, :token
|
137
|
+
config.cc = :email # :full, :hash, :token
|
127
138
|
config.from = :email # :full, :token, :hash
|
128
139
|
# :raw => 'AppName <s13.6b2d13dc6a1d33db7644@mail.myapp.com>'
|
129
140
|
# :email => 's13.6b2d13dc6a1d33db7644@mail.myapp.com'
|
130
141
|
# :token => 's13.6b2d13dc6a1d33db7644'
|
131
|
-
# :hash => { raw: [...], email: [...], token: [...], host: [...],
|
132
|
-
name: [...] }
|
142
|
+
# :hash => { raw: [...], email: [...], token: [...], host: [...], name: [...] }
|
133
143
|
config.reply_delimiter = '-- REPLY ABOVE THIS LINE --'
|
134
|
-
config.email_service = :sendgrid # :cloudmailin, :postmark, :mandrill
|
144
|
+
config.email_service = :sendgrid # :cloudmailin, :postmark, :mandrill, :mailgun
|
135
145
|
end
|
136
146
|
```
|
137
147
|
|
138
148
|
* `config.processor_class` is the class Griddler will use to handle your incoming emails.
|
149
|
+
* `config.processor_method` is the method Griddler will call on the processor class when handling your incoming emails.
|
139
150
|
* `config.reply_delimiter` is the string searched for that will split your body.
|
140
|
-
* `config.to` and `config.from` are the format of the returned value for that
|
151
|
+
* `config.to`, `config.cc` and `config.from` are the format of the returned value for that
|
141
152
|
address in the email object. `:hash` will return all options within a -- (surprise!) -- hash.
|
142
153
|
* `config.email_service` tells Griddler which email service you are using. The
|
143
154
|
supported email service options are `:sendgrid` (the default), `:cloudmailin`
|
@@ -241,7 +252,7 @@ application that can handle the HEAD request:
|
|
241
252
|
|
242
253
|
```ruby
|
243
254
|
# routes.rb
|
244
|
-
get
|
255
|
+
get "/email_processor", to: proc { [200, {}, ["OK"]] }, as: "mandrill_head_test_request"
|
245
256
|
```
|
246
257
|
|
247
258
|
Once you have correctly configured Mandrill, you can go ahead and delete this code.
|
@@ -257,6 +268,8 @@ More Information
|
|
257
268
|
* [Postmark Docs](http://developer.postmarkapp.com/)
|
258
269
|
* [Mandrill](http://mandrill.com)
|
259
270
|
* [Mandrill Docs](http://help.mandrill.com/forums/21092258-Inbound-Email-Processing)
|
271
|
+
* [Mailgun](http://mailgun.com)
|
272
|
+
* [Mailgun Docs](http://documentation.mailgun.com/user_manual.html#receiving-forwarding-and-storing-messages)
|
260
273
|
|
261
274
|
Credits
|
262
275
|
-------
|
data/lib/griddler.rb
CHANGED
@@ -10,6 +10,7 @@ require 'griddler/adapters/sendgrid_adapter'
|
|
10
10
|
require 'griddler/adapters/cloudmailin_adapter'
|
11
11
|
require 'griddler/adapters/postmark_adapter'
|
12
12
|
require 'griddler/adapters/mandrill_adapter'
|
13
|
+
require 'griddler/adapters/mailgun_adapter'
|
13
14
|
|
14
15
|
module Griddler
|
15
16
|
end
|
@@ -13,6 +13,7 @@ module Griddler
|
|
13
13
|
def normalize_params
|
14
14
|
{
|
15
15
|
to: params[:envelope][:to].split(','),
|
16
|
+
cc: ccs,
|
16
17
|
from: params[:envelope][:from],
|
17
18
|
subject: params[:headers][:Subject],
|
18
19
|
text: params[:plain],
|
@@ -24,6 +25,10 @@ module Griddler
|
|
24
25
|
|
25
26
|
attr_reader :params
|
26
27
|
|
28
|
+
def ccs
|
29
|
+
params[:headers][:Cc].to_s.split(',').map(&:strip)
|
30
|
+
end
|
31
|
+
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Griddler
|
2
|
+
module Adapters
|
3
|
+
class MailgunAdapter
|
4
|
+
def initialize(params)
|
5
|
+
@params = params
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.normalize_params(params)
|
9
|
+
adapter = new(params)
|
10
|
+
adapter.normalize_params
|
11
|
+
end
|
12
|
+
|
13
|
+
def normalize_params
|
14
|
+
params.merge(
|
15
|
+
to: recipients,
|
16
|
+
cc: ccs,
|
17
|
+
text: params['body-plain'],
|
18
|
+
html: params['body-html'],
|
19
|
+
headers: params['message-headers'],
|
20
|
+
attachments: attachment_files
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :params
|
27
|
+
|
28
|
+
def recipients
|
29
|
+
params[:recipient].split(',')
|
30
|
+
end
|
31
|
+
|
32
|
+
def ccs
|
33
|
+
cc = if params[:Cc].present?
|
34
|
+
params[:Cc]
|
35
|
+
else
|
36
|
+
extract_header_cc
|
37
|
+
end
|
38
|
+
cc.split(',').map(&:strip)
|
39
|
+
end
|
40
|
+
|
41
|
+
def extract_header_cc
|
42
|
+
header = params['message-headers'].select{|h|
|
43
|
+
h.first == 'Cc'
|
44
|
+
}.first
|
45
|
+
header.to_a.last
|
46
|
+
end
|
47
|
+
|
48
|
+
def attachment_files
|
49
|
+
attachment_count = params['attachment-count'].to_i
|
50
|
+
|
51
|
+
attachment_count.times.map do |index|
|
52
|
+
params.delete("attachment-#{index+1}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -14,7 +14,8 @@ module Griddler
|
|
14
14
|
events.map do |event|
|
15
15
|
{
|
16
16
|
to: recipients(event),
|
17
|
-
|
17
|
+
cc: ccs(event),
|
18
|
+
from: full_email([ event[:from_email], event[:from_name] ]),
|
18
19
|
subject: event[:subject],
|
19
20
|
text: event[:text],
|
20
21
|
html: event[:html],
|
@@ -38,6 +39,11 @@ module Griddler
|
|
38
39
|
event[:to].map { |recipient| full_email(recipient) }
|
39
40
|
end
|
40
41
|
|
42
|
+
def ccs(event)
|
43
|
+
found = event[:headers].select { |header| header.first == 'Cc' }.first
|
44
|
+
Array(found).last.to_s.split(',').map(&:strip)
|
45
|
+
end
|
46
|
+
|
41
47
|
def full_email(contact_info)
|
42
48
|
email = contact_info[0]
|
43
49
|
if contact_info[1]
|
@@ -12,7 +12,8 @@ module Griddler
|
|
12
12
|
|
13
13
|
def normalize_params
|
14
14
|
{
|
15
|
-
to: extract_recipients,
|
15
|
+
to: extract_recipients(:ToFull),
|
16
|
+
cc: extract_recipients(:CcFull),
|
16
17
|
from: full_email(params[:FromFull]),
|
17
18
|
subject: params[:Subject],
|
18
19
|
text: params[:TextBody],
|
@@ -25,8 +26,8 @@ module Griddler
|
|
25
26
|
|
26
27
|
attr_reader :params
|
27
28
|
|
28
|
-
def extract_recipients
|
29
|
-
params[
|
29
|
+
def extract_recipients(key)
|
30
|
+
params[key].to_a.map { |recipient| full_email(recipient) }
|
30
31
|
end
|
31
32
|
|
32
33
|
def full_email(contact_info)
|
@@ -12,7 +12,8 @@ module Griddler
|
|
12
12
|
|
13
13
|
def normalize_params
|
14
14
|
params.merge(
|
15
|
-
to: recipients,
|
15
|
+
to: recipients(:to),
|
16
|
+
cc: recipients(:cc),
|
16
17
|
attachments: attachment_files,
|
17
18
|
)
|
18
19
|
end
|
@@ -21,8 +22,8 @@ module Griddler
|
|
21
22
|
|
22
23
|
attr_reader :params
|
23
24
|
|
24
|
-
def recipients
|
25
|
-
params[
|
25
|
+
def recipients(key)
|
26
|
+
( params[key] || '' ).split(',')
|
26
27
|
end
|
27
28
|
|
28
29
|
def attachment_files
|
@@ -16,7 +16,7 @@ module Griddler
|
|
16
16
|
end
|
17
17
|
|
18
18
|
class Configuration
|
19
|
-
attr_accessor :processor_class, :reply_delimiter, :from
|
19
|
+
attr_accessor :processor_class, :processor_method, :reply_delimiter, :cc, :from
|
20
20
|
|
21
21
|
def to
|
22
22
|
@to ||= :hash
|
@@ -33,6 +33,10 @@ module Griddler
|
|
33
33
|
@to = type
|
34
34
|
end
|
35
35
|
|
36
|
+
def cc
|
37
|
+
@cc ||= :email
|
38
|
+
end
|
39
|
+
|
36
40
|
def from
|
37
41
|
@from ||= :email
|
38
42
|
end
|
@@ -41,6 +45,10 @@ module Griddler
|
|
41
45
|
@processor_class ||= EmailProcessor
|
42
46
|
end
|
43
47
|
|
48
|
+
def processor_method
|
49
|
+
@processor_method ||= :process
|
50
|
+
end
|
51
|
+
|
44
52
|
def reply_delimiter
|
45
53
|
@reply_delimiter ||= 'Reply ABOVE THIS LINE'
|
46
54
|
end
|
@@ -65,6 +73,7 @@ module Griddler
|
|
65
73
|
cloudmailin: Griddler::Adapters::CloudmailinAdapter,
|
66
74
|
postmark: Griddler::Adapters::PostmarkAdapter,
|
67
75
|
mandrill: Griddler::Adapters::MandrillAdapter,
|
76
|
+
mailgun: Griddler::Adapters::MailgunAdapter
|
68
77
|
}
|
69
78
|
end
|
70
79
|
end
|
data/lib/griddler/email.rb
CHANGED
@@ -3,13 +3,13 @@ require 'htmlentities'
|
|
3
3
|
module Griddler
|
4
4
|
class Email
|
5
5
|
include ActionView::Helpers::SanitizeHelper
|
6
|
-
attr_reader :to, :from, :subject, :body, :raw_body, :raw_text, :raw_html,
|
6
|
+
attr_reader :to, :from, :cc, :subject, :body, :raw_body, :raw_text, :raw_html,
|
7
7
|
:headers, :raw_headers, :attachments
|
8
8
|
|
9
9
|
def initialize(params)
|
10
10
|
@params = params
|
11
11
|
|
12
|
-
@to = recipients
|
12
|
+
@to = recipients(:to)
|
13
13
|
@from = extract_address(params[:from], config.from)
|
14
14
|
@subject = params[:subject]
|
15
15
|
|
@@ -19,14 +19,18 @@ module Griddler
|
|
19
19
|
@raw_body = @raw_text || @raw_html
|
20
20
|
|
21
21
|
@headers = extract_headers
|
22
|
+
|
23
|
+
@cc = recipients(:cc)
|
24
|
+
|
22
25
|
@raw_headers = params[:headers]
|
23
26
|
|
24
27
|
@attachments = params[:attachments]
|
25
28
|
end
|
26
29
|
|
27
30
|
def process
|
28
|
-
processor_class
|
29
|
-
|
31
|
+
processor_class = config.processor_class
|
32
|
+
processor_method = config.processor_method
|
33
|
+
processor_class.public_send(processor_method, self)
|
30
34
|
end
|
31
35
|
|
32
36
|
private
|
@@ -34,11 +38,11 @@ module Griddler
|
|
34
38
|
attr_reader :params
|
35
39
|
|
36
40
|
def config
|
37
|
-
Griddler.configuration
|
41
|
+
@config ||= Griddler.configuration
|
38
42
|
end
|
39
43
|
|
40
|
-
def recipients
|
41
|
-
params[
|
44
|
+
def recipients(type=:to)
|
45
|
+
params[type].to_a.map { |recipient| extract_address(recipient, config.send(type)) }
|
42
46
|
end
|
43
47
|
|
44
48
|
def extract_address(address, type)
|
@@ -59,6 +63,10 @@ module Griddler
|
|
59
63
|
EmailParser.extract_headers(params[:headers])
|
60
64
|
end
|
61
65
|
|
66
|
+
def extract_cc_from_headers(headers)
|
67
|
+
EmailParser.extract_cc(headers)
|
68
|
+
end
|
69
|
+
|
62
70
|
def text_or_sanitized_html
|
63
71
|
if params.key? :text
|
64
72
|
clean_text(params[:text])
|
@@ -68,33 +76,24 @@ module Griddler
|
|
68
76
|
end
|
69
77
|
|
70
78
|
def clean_text(text)
|
71
|
-
clean_invalid_utf8_bytes(text
|
79
|
+
clean_invalid_utf8_bytes(text)
|
72
80
|
end
|
73
81
|
|
74
82
|
def clean_html(html)
|
75
|
-
cleaned_html = clean_invalid_utf8_bytes(html
|
83
|
+
cleaned_html = clean_invalid_utf8_bytes(html)
|
76
84
|
cleaned_html = strip_tags(cleaned_html)
|
77
85
|
cleaned_html = HTMLEntities.new.decode(cleaned_html)
|
78
86
|
cleaned_html
|
79
87
|
end
|
80
88
|
|
81
|
-
def clean_invalid_utf8_bytes(text
|
82
|
-
text.
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
undef: :replace,
|
87
|
-
replace: ''
|
88
|
-
)
|
89
|
-
end
|
90
|
-
|
91
|
-
def src_encoding(email_part)
|
92
|
-
if params[:charsets]
|
93
|
-
charsets = ActiveSupport::JSON.decode(params[:charsets])
|
94
|
-
charsets[email_part]
|
95
|
-
else
|
96
|
-
'binary'
|
89
|
+
def clean_invalid_utf8_bytes(text)
|
90
|
+
if !text.valid_encoding?
|
91
|
+
text = text
|
92
|
+
.force_encoding('ISO-8859-1')
|
93
|
+
.encode('UTF-8')
|
97
94
|
end
|
95
|
+
|
96
|
+
text
|
98
97
|
end
|
99
98
|
end
|
100
99
|
end
|
@@ -74,10 +74,12 @@ module Griddler::EmailParser
|
|
74
74
|
def self.regex_split_points
|
75
75
|
[
|
76
76
|
reply_delimeter_regex,
|
77
|
-
/^\s*[-]+\s*Original Message\s*[-]+\s
|
77
|
+
/^\s*[-]+\s*Original Message\s*[-]+\s*$/i,
|
78
78
|
/^\s*--\s*$/,
|
79
|
+
/^\s*\>?\s*On.*\r?\n?\s*.*\s*wrote:$/,
|
79
80
|
/On.*wrote:/,
|
80
|
-
|
81
|
+
/From:.*$/i,
|
82
|
+
/^\s*\d{4}\/\d{1,2}\/\d{1,2}\s.*\s<.*>?$/i
|
81
83
|
]
|
82
84
|
end
|
83
85
|
|
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.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caleb Thompson
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2014-01-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -92,10 +92,15 @@ executables: []
|
|
92
92
|
extensions: []
|
93
93
|
extra_rdoc_files: []
|
94
94
|
files:
|
95
|
+
- LICENSE
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
95
98
|
- app/controllers/griddler/emails_controller.rb
|
96
99
|
- config/initializers/griddler.rb
|
97
100
|
- config/routes.rb
|
101
|
+
- lib/griddler.rb
|
98
102
|
- lib/griddler/adapters/cloudmailin_adapter.rb
|
103
|
+
- lib/griddler/adapters/mailgun_adapter.rb
|
99
104
|
- lib/griddler/adapters/mandrill_adapter.rb
|
100
105
|
- lib/griddler/adapters/postmark_adapter.rb
|
101
106
|
- lib/griddler/adapters/sendgrid_adapter.rb
|
@@ -106,11 +111,7 @@ files:
|
|
106
111
|
- lib/griddler/errors.rb
|
107
112
|
- lib/griddler/route_extensions.rb
|
108
113
|
- lib/griddler/version.rb
|
109
|
-
- lib/griddler.rb
|
110
114
|
- lib/tasks/griddler_tasks.rake
|
111
|
-
- LICENSE
|
112
|
-
- Rakefile
|
113
|
-
- README.md
|
114
115
|
homepage: http://thoughtbot.com
|
115
116
|
licenses: []
|
116
117
|
metadata: {}
|
@@ -134,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
135
|
version: '0'
|
135
136
|
requirements: []
|
136
137
|
rubyforge_project:
|
137
|
-
rubygems_version: 2.
|
138
|
+
rubygems_version: 2.2.1
|
138
139
|
signing_key:
|
139
140
|
specification_version: 4
|
140
141
|
summary: SendGrid Parse API client Rails Engine
|