griddler 0.6.1 → 0.6.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 01c15f81e30fcd63ca2c9cb4bc9e2e8678264c5f
4
- data.tar.gz: 37a8b24a5ce5b94ef4e7f7d907298abfb3517cd2
3
+ metadata.gz: c93ac0eaccf2bf366151a3d202d31fb80c955e3a
4
+ data.tar.gz: 7966242ad3ac5d8566b8ed991b3b1118f266d88d
5
5
  SHA512:
6
- metadata.gz: 44c21089a2ede6e88242b9e6b24fc38bda03bc0a0dbcbf92e74e0a4a792d000cc374bcbb1da8e99bc922e934dbf8fa4506c164034293ebb482c62c80c1a8ece0
7
- data.tar.gz: 82704ef5699bc9c2b5c8fa1f274a21f37bb63993f6da44d74f273414d4464c2fea834464afe1f77919c1bd9a88abeb46ea7adeeb4676feaa8aa19562cf2d8a15
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
- In `config/routes.rb` you may either use the provided method `mount_griddler`
35
- or set the route manually. Examples:
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/initializer/griddler.rb`:
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 '/email_processor', :to => proc { [200, {}, ["OK"]] }
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
- from: event[:from_email],
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[:ToFull].map { |recipient| full_email(recipient) }
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[:to].split(',')
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
@@ -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 = config.processor_class
29
- processor_class.process(self)
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[:to].map { |recipient| extract_address(recipient, config.to) }
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, '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, '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, email_part)
82
- text.encode(
83
- 'UTF-8',
84
- src_encoding(email_part),
85
- invalid: :replace,
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
- /^\s*On.*\r?\n?\s*.*\s*wrote:$/
81
+ /From:.*$/i,
82
+ /^\s*\d{4}\/\d{1,2}\/\d{1,2}\s.*\s<.*>?$/i
81
83
  ]
82
84
  end
83
85
 
@@ -1,3 +1,3 @@
1
1
  module Griddler
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.3"
3
3
  end
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.1
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: 2013-09-04 00:00:00.000000000 Z
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.0.5
138
+ rubygems_version: 2.2.1
138
139
  signing_key:
139
140
  specification_version: 4
140
141
  summary: SendGrid Parse API client Rails Engine