griddler 0.3.1 → 0.4.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.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +63 -15
- data/app/controllers/griddler/emails_controller.rb +7 -1
- data/config/routes.rb +1 -1
- data/lib/griddler.rb +5 -1
- data/lib/griddler/adapters/cloudmailin_adapter.rb +29 -0
- data/lib/griddler/adapters/postmark_adapter.rb +49 -0
- data/lib/griddler/adapters/sendgrid_adapter.rb +32 -0
- data/lib/griddler/configuration.rb +21 -6
- data/lib/griddler/email.rb +73 -73
- data/lib/griddler/email_parser.rb +15 -2
- data/lib/griddler/errors.rb +3 -0
- data/lib/griddler/version.rb +1 -1
- metadata +35 -33
- data/lib/griddler/email_format.rb +0 -6
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fb74f34f6940e9e3287bfb7a543d4eed144ca554
|
4
|
+
data.tar.gz: 38c69abc85aed6e97d8d7e75d47456b476964b27
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2cd9c1d15de8639995f8c02f085da8c88846d3226a136756c022cdfb9b9125a0bb1da7d9b4b2aea10274f9d58ee6792d8675ced712f75f9470f6791b1931d40b
|
7
|
+
data.tar.gz: 7d6bce5cd7c9bff557cc6611a7c5129091d104d4e90e1bd031d26d9f7e8f8cb79e28eb12ab162e4c52e4fcf0e015eb5dea3a3c9974daf75d61aeff6d8c8c0b2d
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2013 Caleb Thompson, Joel Oliveira and thoughtbot, inc.
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -1,13 +1,26 @@
|
|
1
|
-
|
2
1
|
Griddler
|
3
2
|
========
|
4
3
|
|
4
|
+
[](https://travis-ci.org/thoughtbot/griddler)
|
5
|
+
[](https://codeclimate.com/github/thoughtbot/griddler)
|
6
|
+
|
5
7
|
### Receive emails in your Rails app
|
6
8
|
|
7
9
|
Griddler is a Rails engine (full plugin) that provides an endpoint for the
|
8
|
-
[
|
10
|
+
[SendGrid parse api](http://sendgrid.com/docs/API%20Reference/Webhooks/parse.html),
|
11
|
+
[Cloudmailin parse api](http://cloudmailin.com) or
|
12
|
+
[Postmark parse api](http://developer.postmarkapp.com/developer-inbound-parse.html)
|
9
13
|
that hands off a built email object to a class implemented by you.
|
10
14
|
|
15
|
+
Tutorials
|
16
|
+
---------
|
17
|
+
|
18
|
+
* SendGrid has done a
|
19
|
+
[great tutorial](http://blog.sendgrid.com/receiving-email-in-your-rails-app-with-griddler/)
|
20
|
+
on integrating Griddler with your application.
|
21
|
+
* And of course, view our own blog post on the subject over at
|
22
|
+
[Giant Robots](http://robots.thoughtbot.com/post/42286882447/handle-incoming-email-with-griddler).
|
23
|
+
|
11
24
|
Installation
|
12
25
|
------------
|
13
26
|
|
@@ -19,11 +32,11 @@ gem 'griddler'
|
|
19
32
|
|
20
33
|
Griddler comes with a default endpoint that will be displayed at the bottom
|
21
34
|
of the output of `rake routes`. If there is a previously defined route that
|
22
|
-
matches `/email_processor
|
35
|
+
matches `/email_processor` -- or you would like to rename the matched path -- you
|
23
36
|
may add the route to the desired position in routes.rb with the following:
|
24
37
|
|
25
38
|
```ruby
|
26
|
-
|
39
|
+
post '/email_processor' => 'griddler/emails#create'
|
27
40
|
```
|
28
41
|
|
29
42
|
Defaults
|
@@ -50,10 +63,14 @@ that responds to:
|
|
50
63
|
* `.subject`
|
51
64
|
* `.body`
|
52
65
|
* `.raw_body`
|
66
|
+
* `.attachments`
|
67
|
+
* `.headers`
|
68
|
+
* `.raw_headers`
|
53
69
|
|
54
70
|
Each of those has some sensible defaults.
|
55
71
|
|
56
|
-
`.from`, `.raw_body
|
72
|
+
`.from`, `.raw_body`, `.raw_headers`, and `.subject` will contain the obvious
|
73
|
+
values found in the email, the raw values from those fields.
|
57
74
|
|
58
75
|
`.body` will contain the full contents of the email body **unless** there is a
|
59
76
|
line in the email containing the string `-- Reply ABOVE THIS LINE --`. In that
|
@@ -63,6 +80,12 @@ case `.body` will contain everything before that line.
|
|
63
80
|
that this is the most often used portion of the email address and consider it to
|
64
81
|
be the token we'll key off of for interaction with our application.
|
65
82
|
|
83
|
+
`.attachments` will contain an array of attachments as multipart/form-data files
|
84
|
+
which can be passed off to attachment libraries like Carrierwave or Paperclip.
|
85
|
+
|
86
|
+
`.headers` will contain a hash of header names and values as parsed by the Mail
|
87
|
+
gem. Headers will only be parsed if the adapter supports a headers option.
|
88
|
+
|
66
89
|
Configuration Options
|
67
90
|
---------------------
|
68
91
|
|
@@ -78,13 +101,17 @@ Griddler.configure do |config|
|
|
78
101
|
# :token => 's13.6b2d13dc6a1d33db7644'
|
79
102
|
# :hash => { raw: '', email: '', token: '', host: '' }
|
80
103
|
config.reply_delimiter = '-- REPLY ABOVE THIS LINE --'
|
104
|
+
config.email_service = :sendgrid
|
81
105
|
end
|
82
106
|
```
|
83
107
|
|
84
|
-
* `config.processor_class`
|
85
|
-
* `config.reply_delimiter`
|
86
|
-
* `config.to`
|
108
|
+
* `config.processor_class` is the class Griddler will use to handle your incoming emails.
|
109
|
+
* `config.reply_delimiter` is the string searched for that will split your body.
|
110
|
+
* `config.to` is the format of the returned value for the `:to` key in
|
87
111
|
the email object. `:hash` will return all options within a -- (surprise!) -- hash.
|
112
|
+
* `config.email_service` tells Griddler which email service you are using. The supported
|
113
|
+
email service options are :sendgrid (the default), :cloudmailin (expects
|
114
|
+
multipart format) and :postmark
|
88
115
|
|
89
116
|
Testing In Your App
|
90
117
|
-------------------
|
@@ -113,18 +140,39 @@ factory :email, class: OpenStruct do
|
|
113
140
|
end
|
114
141
|
```
|
115
142
|
|
116
|
-
Bear in mind, if you plan on using the
|
117
|
-
example assumes your factories are in spec/factories.rb and you have
|
118
|
-
an image file in spec/fixtures
|
143
|
+
Bear in mind, if you plan on using the `:with_attachment` trait, that this
|
144
|
+
example assumes your factories are in `spec/factories.rb` and you have
|
145
|
+
an image file in `spec/fixtures/`.
|
119
146
|
|
120
147
|
To use it in your test(s) just build with `email = build(:email)`
|
121
|
-
or `email = build(:email, :with_attachment)
|
148
|
+
or `email = build(:email, :with_attachment)`.
|
149
|
+
|
150
|
+
Adapters
|
151
|
+
--------
|
152
|
+
|
153
|
+
`Griddler::Email` expects certain parameters to be in place for proper parsing
|
154
|
+
to occur. When writing an adapter, ensure that the `normalized_params` method
|
155
|
+
of your adapter returns a hash with these keys:
|
156
|
+
|
157
|
+
* `:to` The recipient field
|
158
|
+
* `:from` The sender field
|
159
|
+
* `:subject` Email subject
|
160
|
+
* `:text` The text body of the email
|
161
|
+
* `:html` The html body of the email, nil or empty string if not present
|
162
|
+
* `:attachments` (can be an empty array) Array of attachments to the email
|
163
|
+
* `:headers` (optional) The raw headers of the email
|
164
|
+
* `:charsets` (optional) A JSON string containing the character sets of the
|
165
|
+
fields extracted from the message
|
122
166
|
|
123
167
|
More Information
|
124
168
|
----------------
|
125
169
|
|
126
|
-
* [
|
127
|
-
* [
|
170
|
+
* [SendGrid](http://www.sendgrid.com)
|
171
|
+
* [SendGrid Parse API](http://www.sendgrid.com/docs/API Reference/Webhooks/parse.html)
|
172
|
+
* [Cloudmailin](http://cloudmailin.com)
|
173
|
+
* [Cloudmailin Docs](http://docs.cloudmailin.com/)
|
174
|
+
* [Postmark](http://postmarkapp.com)
|
175
|
+
* [Postmark Docs](http://developer.postmarkapp.com/)
|
128
176
|
|
129
177
|
Credits
|
130
178
|
-------
|
@@ -141,6 +189,6 @@ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
|
141
189
|
License
|
142
190
|
-------
|
143
191
|
|
144
|
-
Griddler is Copyright ©
|
192
|
+
Griddler is Copyright © 2013 Caleb Thompson, Joel Oliveira and thoughtbot. It is
|
145
193
|
free software, and may be redistributed under the terms specified in the LICENSE
|
146
194
|
file.
|
@@ -1,6 +1,12 @@
|
|
1
1
|
class Griddler::EmailsController < ActionController::Base
|
2
2
|
def create
|
3
|
-
Griddler::Email.new(
|
3
|
+
Griddler::Email.new(normalized_params).process
|
4
4
|
head :ok
|
5
5
|
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def normalized_params
|
10
|
+
Griddler.configuration.email_service.normalize_params(params)
|
11
|
+
end
|
6
12
|
end
|
data/config/routes.rb
CHANGED
data/lib/griddler.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'rails/engine'
|
2
|
+
require 'action_view'
|
1
3
|
require 'griddler/errors'
|
2
4
|
require 'griddler/engine'
|
3
5
|
require 'griddler/email'
|
4
|
-
require 'griddler/email_format'
|
5
6
|
require 'griddler/email_parser'
|
6
7
|
require 'griddler/configuration'
|
8
|
+
require 'griddler/adapters/sendgrid_adapter'
|
9
|
+
require 'griddler/adapters/cloudmailin_adapter'
|
10
|
+
require 'griddler/adapters/postmark_adapter'
|
7
11
|
|
8
12
|
module Griddler
|
9
13
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Griddler
|
2
|
+
module Adapters
|
3
|
+
class CloudmailinAdapter
|
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
|
+
{
|
15
|
+
to: params[:envelope][:to],
|
16
|
+
from: params[:envelope][:from],
|
17
|
+
subject: params[:headers][:Subject],
|
18
|
+
text: params[:plain],
|
19
|
+
attachments: params.fetch(:attachments) { [] },
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :params
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Griddler
|
2
|
+
module Adapters
|
3
|
+
class PostmarkAdapter
|
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
|
+
{
|
15
|
+
to: params[:ToFull][:Email],
|
16
|
+
from: params[:FromFull][:Email],
|
17
|
+
subject: params[:Subject],
|
18
|
+
text: params[:TextBody],
|
19
|
+
html: params[:HtmlBody],
|
20
|
+
attachments: attachment_files,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :params
|
27
|
+
|
28
|
+
def attachment_files
|
29
|
+
attachments = Array(params[:Attachments])
|
30
|
+
|
31
|
+
attachments.map do |attachment|
|
32
|
+
ActionDispatch::Http::UploadedFile.new({
|
33
|
+
filename: attachment[:Name],
|
34
|
+
type: attachment[:ContentType],
|
35
|
+
tempfile: create_tempfile(attachment)
|
36
|
+
})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_tempfile(attachment)
|
41
|
+
filename = attachment[:Name]
|
42
|
+
tempfile = Tempfile.new(filename, Dir::tmpdir, encoding: 'ascii-8bit')
|
43
|
+
tempfile.write(Base64.decode64(attachment[:Content]))
|
44
|
+
tempfile.rewind
|
45
|
+
tempfile
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Griddler
|
2
|
+
module Adapters
|
3
|
+
class SendgridAdapter
|
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[:attachments] = attachment_files
|
15
|
+
params
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :params
|
21
|
+
|
22
|
+
def attachment_files
|
23
|
+
params.delete('attachment-info')
|
24
|
+
attachment_count = params[:attachments].to_i
|
25
|
+
|
26
|
+
attachment_count.times.map do |index|
|
27
|
+
params.delete("attachment#{index + 1}".to_sym)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,20 +1,18 @@
|
|
1
1
|
module Griddler
|
2
|
-
|
3
|
-
attr_accessor :configuration
|
4
|
-
end
|
2
|
+
@@configuration = nil
|
5
3
|
|
6
4
|
def self.configure
|
7
|
-
|
5
|
+
@@configuration = Configuration.new
|
8
6
|
|
9
7
|
if block_given?
|
10
8
|
yield configuration
|
11
9
|
end
|
12
10
|
|
13
|
-
|
11
|
+
configuration
|
14
12
|
end
|
15
13
|
|
16
14
|
def self.configuration
|
17
|
-
|
15
|
+
@@configuration || configure
|
18
16
|
end
|
19
17
|
|
20
18
|
class Configuration
|
@@ -31,5 +29,22 @@ module Griddler
|
|
31
29
|
def reply_delimiter
|
32
30
|
@reply_delimiter ||= 'Reply ABOVE THIS LINE'
|
33
31
|
end
|
32
|
+
|
33
|
+
def email_service
|
34
|
+
@email_service_adapter ||= adapter_class[:sendgrid]
|
35
|
+
end
|
36
|
+
|
37
|
+
def email_service=(new_email_service)
|
38
|
+
@email_service_adapter = adapter_class.fetch(new_email_service) { raise Griddler::Errors::EmailServiceAdapterNotFound }
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def adapter_class
|
44
|
+
{
|
45
|
+
sendgrid: Griddler::Adapters::SendgridAdapter,
|
46
|
+
cloudmailin: Griddler::Adapters::CloudmailinAdapter,
|
47
|
+
}
|
48
|
+
end
|
34
49
|
end
|
35
50
|
end
|
data/lib/griddler/email.rb
CHANGED
@@ -1,96 +1,96 @@
|
|
1
1
|
require 'htmlentities'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@params = params
|
9
|
-
@to = extract_address(params[:to], config.to)
|
10
|
-
@from = extract_address(params[:from], :email)
|
11
|
-
@subject = params[:subject]
|
12
|
-
@body = extract_body
|
13
|
-
@raw_body = params[:text] || params[:html]
|
14
|
-
@attachments = extract_attachments
|
15
|
-
|
16
|
-
processor_class = config.processor_class
|
17
|
-
processor_class.process(self)
|
18
|
-
end
|
3
|
+
module Griddler
|
4
|
+
class Email
|
5
|
+
include ActionView::Helpers::SanitizeHelper
|
6
|
+
attr_reader :to, :from, :subject, :body, :raw_body,
|
7
|
+
:headers, :raw_headers, :attachments
|
19
8
|
|
20
|
-
|
9
|
+
def initialize(params)
|
10
|
+
@params = params
|
21
11
|
|
22
|
-
|
12
|
+
@to = extract_address(params[:to], config.to)
|
13
|
+
@from = extract_address(params[:from], :email)
|
14
|
+
@subject = params[:subject]
|
23
15
|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
16
|
+
@body = extract_body
|
17
|
+
@raw_body = params[:text] || params[:html]
|
27
18
|
|
28
|
-
|
29
|
-
|
19
|
+
@headers = extract_headers
|
20
|
+
@raw_headers = params[:headers]
|
30
21
|
|
31
|
-
|
32
|
-
parsed
|
33
|
-
else
|
34
|
-
parsed[type]
|
22
|
+
@attachments = params[:attachments]
|
35
23
|
end
|
36
|
-
end
|
37
24
|
|
38
|
-
|
39
|
-
|
40
|
-
|
25
|
+
def process
|
26
|
+
processor_class = config.processor_class
|
27
|
+
processor_class.process(self)
|
28
|
+
end
|
41
29
|
|
42
|
-
|
43
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :params
|
33
|
+
|
34
|
+
def config
|
35
|
+
Griddler.configuration
|
44
36
|
end
|
45
37
|
|
46
|
-
|
47
|
-
|
38
|
+
def extract_address(address, type)
|
39
|
+
parsed = EmailParser.parse_address(address)
|
48
40
|
|
49
|
-
|
50
|
-
|
51
|
-
|
41
|
+
if type == :hash
|
42
|
+
parsed
|
43
|
+
else
|
44
|
+
parsed[type]
|
45
|
+
end
|
46
|
+
end
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
body_text = body_text.encode(
|
56
|
-
'UTF-8',
|
57
|
-
invalid: :replace,
|
58
|
-
undef: :replace,
|
59
|
-
replace: ''
|
60
|
-
).force_encoding('UTF-8')
|
48
|
+
def extract_body
|
49
|
+
EmailParser.extract_reply_body(text_or_sanitized_html)
|
61
50
|
end
|
62
51
|
|
63
|
-
|
64
|
-
|
52
|
+
def extract_headers
|
53
|
+
EmailParser.extract_headers(params[:headers])
|
54
|
+
end
|
65
55
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
56
|
+
def text_or_sanitized_html
|
57
|
+
if params.key? :text
|
58
|
+
clean_text(params[:text])
|
59
|
+
elsif params.key? :html
|
60
|
+
clean_html(params[:html])
|
61
|
+
else
|
62
|
+
raise Errors::EmailBodyNotFound
|
63
|
+
end
|
73
64
|
end
|
74
|
-
end
|
75
65
|
|
76
|
-
|
77
|
-
|
78
|
-
|
66
|
+
def clean_text(text)
|
67
|
+
clean_invalid_utf8_bytes(text, 'text')
|
68
|
+
end
|
79
69
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
70
|
+
def clean_html(html)
|
71
|
+
cleaned_html = clean_invalid_utf8_bytes(html, 'html')
|
72
|
+
cleaned_html = strip_tags(cleaned_html)
|
73
|
+
cleaned_html = HTMLEntities.new.decode(cleaned_html)
|
74
|
+
cleaned_html
|
75
|
+
end
|
86
76
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
77
|
+
def clean_invalid_utf8_bytes(text, email_part)
|
78
|
+
text.encode(
|
79
|
+
'UTF-8',
|
80
|
+
src_encoding(email_part),
|
81
|
+
invalid: :replace,
|
82
|
+
undef: :replace,
|
83
|
+
replace: ''
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def src_encoding(email_part)
|
88
|
+
if params[:charsets]
|
89
|
+
charsets = ActiveSupport::JSON.decode(params[:charsets])
|
90
|
+
charsets[email_part]
|
91
|
+
else
|
92
|
+
'binary'
|
93
|
+
end
|
94
|
+
end
|
95
95
|
end
|
96
96
|
end
|
@@ -8,7 +8,9 @@
|
|
8
8
|
# email: 'somebody@example.com',
|
9
9
|
# full: 'Some Body <somebody@example.com>',
|
10
10
|
# }
|
11
|
-
|
11
|
+
require 'mail'
|
12
|
+
|
13
|
+
module Griddler::EmailParser
|
12
14
|
def self.parse_address(full_address)
|
13
15
|
email_address = extract_email_address(full_address)
|
14
16
|
token, host = split_address(email_address)
|
@@ -21,7 +23,9 @@ module EmailParser
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def self.extract_reply_body(body)
|
24
|
-
if body
|
26
|
+
if body.blank?
|
27
|
+
""
|
28
|
+
else
|
25
29
|
delimeter = Griddler.configuration.reply_delimiter
|
26
30
|
body.split(delimeter).first.
|
27
31
|
split(/^\s*[-]+\s*Original Message\s*[-]+\s*$/).first.
|
@@ -37,6 +41,15 @@ module EmailParser
|
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
44
|
+
def self.extract_headers(raw_headers)
|
45
|
+
header_fields = Mail::Header.new(raw_headers).fields
|
46
|
+
|
47
|
+
header_fields.inject({}) do |header_hash, header_field|
|
48
|
+
header_hash[header_field.name.to_s] = header_field.value.to_s
|
49
|
+
header_hash
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
40
53
|
private
|
41
54
|
|
42
55
|
def self.extract_email_address(full_address)
|
data/lib/griddler/errors.rb
CHANGED
data/lib/griddler/version.rb
CHANGED
metadata
CHANGED
@@ -1,86 +1,93 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: griddler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Caleb Thompson
|
9
8
|
- Joel Oliveira
|
10
9
|
- thoughtbot
|
10
|
+
- Swift
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-
|
14
|
+
date: 2013-03-18 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
19
|
requirements:
|
21
|
-
- -
|
20
|
+
- - '>='
|
22
21
|
- !ruby/object:Gem::Version
|
23
22
|
version: 3.2.0
|
24
23
|
type: :runtime
|
25
24
|
prerelease: false
|
26
25
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
28
26
|
requirements:
|
29
|
-
- -
|
27
|
+
- - '>='
|
30
28
|
- !ruby/object:Gem::Version
|
31
29
|
version: 3.2.0
|
32
30
|
- !ruby/object:Gem::Dependency
|
33
31
|
name: htmlentities
|
34
32
|
requirement: !ruby/object:Gem::Requirement
|
35
|
-
none: false
|
36
33
|
requirements:
|
37
|
-
- -
|
34
|
+
- - '>='
|
38
35
|
- !ruby/object:Gem::Version
|
39
36
|
version: '0'
|
40
37
|
type: :runtime
|
41
38
|
prerelease: false
|
42
39
|
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
40
|
requirements:
|
45
|
-
- -
|
41
|
+
- - '>='
|
46
42
|
- !ruby/object:Gem::Version
|
47
43
|
version: '0'
|
48
44
|
- !ruby/object:Gem::Dependency
|
49
45
|
name: rspec-rails
|
50
46
|
requirement: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
47
|
requirements:
|
53
|
-
- -
|
48
|
+
- - '>='
|
54
49
|
- !ruby/object:Gem::Version
|
55
50
|
version: '0'
|
56
51
|
type: :development
|
57
52
|
prerelease: false
|
58
53
|
version_requirements: !ruby/object:Gem::Requirement
|
59
|
-
none: false
|
60
54
|
requirements:
|
61
|
-
- -
|
55
|
+
- - '>='
|
62
56
|
- !ruby/object:Gem::Version
|
63
57
|
version: '0'
|
64
58
|
- !ruby/object:Gem::Dependency
|
65
59
|
name: sqlite3
|
66
60
|
requirement: !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
61
|
requirements:
|
69
|
-
- -
|
62
|
+
- - '>='
|
70
63
|
- !ruby/object:Gem::Version
|
71
64
|
version: '0'
|
72
65
|
type: :development
|
73
66
|
prerelease: false
|
74
67
|
version_requirements: !ruby/object:Gem::Requirement
|
75
|
-
none: false
|
76
68
|
requirements:
|
77
|
-
- -
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: jquery-rails
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
78
84
|
- !ruby/object:Gem::Version
|
79
85
|
version: '0'
|
80
86
|
description:
|
81
87
|
email:
|
82
88
|
- cjaysson@gmail.com
|
83
89
|
- joel@thoughtbot.com
|
90
|
+
- theycallmeswift@gmail.com
|
84
91
|
executables: []
|
85
92
|
extensions: []
|
86
93
|
extra_rdoc_files: []
|
@@ -88,9 +95,11 @@ files:
|
|
88
95
|
- app/controllers/griddler/emails_controller.rb
|
89
96
|
- config/initializers/griddler.rb
|
90
97
|
- config/routes.rb
|
98
|
+
- lib/griddler/adapters/cloudmailin_adapter.rb
|
99
|
+
- lib/griddler/adapters/postmark_adapter.rb
|
100
|
+
- lib/griddler/adapters/sendgrid_adapter.rb
|
91
101
|
- lib/griddler/configuration.rb
|
92
102
|
- lib/griddler/email.rb
|
93
|
-
- lib/griddler/email_format.rb
|
94
103
|
- lib/griddler/email_parser.rb
|
95
104
|
- lib/griddler/engine.rb
|
96
105
|
- lib/griddler/errors.rb
|
@@ -102,33 +111,26 @@ files:
|
|
102
111
|
- README.md
|
103
112
|
homepage: http://thoughtbot.com
|
104
113
|
licenses: []
|
114
|
+
metadata: {}
|
105
115
|
post_install_message:
|
106
116
|
rdoc_options: []
|
107
117
|
require_paths:
|
108
118
|
- app
|
109
119
|
- lib
|
110
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
-
none: false
|
112
121
|
requirements:
|
113
|
-
- -
|
122
|
+
- - '>='
|
114
123
|
- !ruby/object:Gem::Version
|
115
|
-
version:
|
116
|
-
segments:
|
117
|
-
- 0
|
118
|
-
hash: 4165747324942510967
|
124
|
+
version: 1.9.2
|
119
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
-
none: false
|
121
126
|
requirements:
|
122
|
-
- -
|
127
|
+
- - '>='
|
123
128
|
- !ruby/object:Gem::Version
|
124
129
|
version: '0'
|
125
|
-
segments:
|
126
|
-
- 0
|
127
|
-
hash: 4165747324942510967
|
128
130
|
requirements: []
|
129
131
|
rubyforge_project:
|
130
|
-
rubygems_version:
|
132
|
+
rubygems_version: 2.0.0
|
131
133
|
signing_key:
|
132
|
-
specification_version:
|
134
|
+
specification_version: 4
|
133
135
|
summary: SendGrid Parse API client Rails Engine
|
134
136
|
test_files: []
|
@@ -1,6 +0,0 @@
|
|
1
|
-
module Griddler::EmailFormat
|
2
|
-
LocalPartSpecialChars = Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
|
3
|
-
LocalPartUnquoted = '(([[:alnum:]' + LocalPartSpecialChars + ']+[\.\+]+))*[[:alnum:]' + LocalPartSpecialChars + '+]+'
|
4
|
-
LocalPartQuoted = '\"(([[:alnum:]' + LocalPartSpecialChars + '\.\+]*|(\\\\[\u0001-\uFFFF]))*)\"'
|
5
|
-
Regex = Regexp.new('((' + LocalPartUnquoted + ')|(' + LocalPartQuoted + ')+)@(((\w+\-+)|(\w+\.))*\w{1,63}\.[a-z]{2,6})', Regexp::EXTENDED | Regexp::IGNORECASE)
|
6
|
-
end
|