multi_mail 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +10 -0
  3. data/README.md +283 -59
  4. data/Rakefile +38 -19
  5. data/lib/multi_mail/cloudmailin/receiver.rb +3 -13
  6. data/lib/multi_mail/mailgun/message.rb +67 -0
  7. data/lib/multi_mail/mailgun/receiver.rb +20 -13
  8. data/lib/multi_mail/mailgun/sender.rb +79 -2
  9. data/lib/multi_mail/mandrill/message.rb +74 -0
  10. data/lib/multi_mail/mandrill/receiver.rb +36 -16
  11. data/lib/multi_mail/mandrill/sender.rb +77 -2
  12. data/lib/multi_mail/message/base.rb +40 -0
  13. data/lib/multi_mail/postmark/receiver.rb +1 -1
  14. data/lib/multi_mail/postmark/sender.rb +35 -5
  15. data/lib/multi_mail/receiver/base.rb +31 -2
  16. data/lib/multi_mail/receiver.rb +1 -4
  17. data/lib/multi_mail/sender/base.rb +23 -1
  18. data/lib/multi_mail/sendgrid/message.rb +74 -0
  19. data/lib/multi_mail/sendgrid/receiver.rb +72 -23
  20. data/lib/multi_mail/sendgrid/sender.rb +63 -2
  21. data/lib/multi_mail/service.rb +48 -56
  22. data/lib/multi_mail/simple/receiver.rb +4 -4
  23. data/lib/multi_mail/version.rb +1 -1
  24. data/lib/multi_mail.rb +16 -1
  25. data/multi_mail.gemspec +4 -1
  26. data/spec/fixtures/empty.gif +0 -0
  27. data/spec/fixtures/mailgun/raw/invalid.txt +13 -0
  28. data/spec/fixtures/mailgun/raw/missing.txt +13 -0
  29. data/spec/fixtures/mailgun/raw/spam.txt +13 -0
  30. data/spec/fixtures/mailgun/raw/valid.txt +13 -0
  31. data/spec/fixtures/mandrill/invalid.txt +15 -0
  32. data/spec/fixtures/mandrill/missing.txt +14 -0
  33. data/spec/fixtures/mandrill/multiple.txt +15 -0
  34. data/spec/fixtures/mandrill/valid.txt +10 -5
  35. data/spec/fixtures/postmark/valid.txt +13 -13
  36. data/spec/fixtures/sendgrid/encoding.txt +90 -0
  37. data/spec/fixtures/sendgrid/spam.txt +94 -0
  38. data/spec/fixtures/sendgrid/valid.txt +136 -0
  39. data/spec/mailgun/message_spec.rb +251 -0
  40. data/spec/mailgun/receiver_spec.rb +35 -20
  41. data/spec/mailgun/sender_spec.rb +175 -0
  42. data/spec/mandrill/message_spec.rb +305 -0
  43. data/spec/mandrill/receiver_spec.rb +90 -46
  44. data/spec/mandrill/sender_spec.rb +138 -0
  45. data/spec/message/base_spec.rb +81 -0
  46. data/spec/postmark/receiver_spec.rb +4 -4
  47. data/spec/postmark/sender_spec.rb +118 -0
  48. data/spec/receiver/base_spec.rb +16 -9
  49. data/spec/sender/base_spec.rb +24 -10
  50. data/spec/sendgrid/message_spec.rb +265 -0
  51. data/spec/sendgrid/receiver_spec.rb +77 -0
  52. data/spec/sendgrid/sender_spec.rb +140 -0
  53. data/spec/service_spec.rb +18 -1
  54. data/spec/simple/receiver_spec.rb +1 -1
  55. data/spec/spec_helper.rb +46 -4
  56. metadata +226 -143
  57. data/lib/multi_mail/sender.rb +0 -46
  58. data/lib/multi_mail/simple/sender.rb +0 -14
  59. data/spec/sender_spec.rb +0 -13
  60. data/spec/simple/sender_spec.rb +0 -0
@@ -20,7 +20,7 @@ describe MultiMail::Receiver::Postmark do
20
20
  # Headers
21
21
  message.date.should == DateTime.parse('Mon, 15 Apr 2013 20:20:12 -0400')
22
22
  message.from.should == ['james@opennorth.ca']
23
- message.to.should == ['4354473e2e6ab001fa836f627a54004e@inbound.postmarkapp.com']
23
+ message.to.should == ['4354473e2e6ab001fa836f627a54004e+bar@inbound.postmarkapp.com']
24
24
  message.subject.should == 'Test'
25
25
 
26
26
  # Body
@@ -39,8 +39,8 @@ describe MultiMail::Receiver::Postmark do
39
39
  attachment1.read.should == "Nam accumsan euismod eros et rhoncus.\n"
40
40
 
41
41
  # Extra Postmark parameters
42
- message['MailboxHash'].should be_nil
43
- message['MessageID'].value.should == '61c7c8b8-ba7e-43c3-b9ad-0ba865e8caa2'
42
+ message['MailboxHash'].value.should == 'bar'
43
+ message['MessageID'].value.should == 'e27500eb-142e-4ca0-8529-e32ffd9931d6'
44
44
  message['Tag'].should be_nil
45
45
  end
46
46
  end
@@ -56,5 +56,5 @@ describe MultiMail::Receiver::Postmark do
56
56
  service.spam?(message).should == false
57
57
  end
58
58
  end
59
- end
59
+ end
60
60
  end
@@ -0,0 +1,118 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'multi_mail/postmark/sender'
3
+
4
+ # @see https://github.com/wildbit/postmark-gem/blob/master/spec/unit/postmark/handlers/mail_spec.rb
5
+ # @see https://github.com/wildbit/postmark-gem/blob/master/spec/integration/mail_delivery_method_spec.rb
6
+ describe MultiMail::Sender::Postmark do
7
+ let :message do
8
+ Mail.new do
9
+ from 'foo@example.com'
10
+ to 'bar@example.com'
11
+ subject 'test'
12
+ body 'hello'
13
+ end
14
+ end
15
+
16
+ let :message_without_from do
17
+ Mail.new do
18
+ date Time.at(946702800)
19
+ to 'bar@example.com'
20
+ subject 'test'
21
+ body 'hello'
22
+ end
23
+ end
24
+
25
+ let :message_without_to do
26
+ Mail.new do
27
+ date Time.at(946702800)
28
+ from 'foo@example.com'
29
+ subject 'test'
30
+ body 'hello'
31
+ end
32
+ end
33
+
34
+ let :message_without_subject do
35
+ Mail.new do
36
+ date Time.at(946702800)
37
+ from 'foo@example.com'
38
+ to 'bar@example.com'
39
+ body 'hello'
40
+ end
41
+ end
42
+
43
+ let :message_without_body do
44
+ Mail.new do
45
+ date Time.at(946702800)
46
+ from 'foo@example.com'
47
+ to 'bar@example.com'
48
+ subject 'test'
49
+ end
50
+ end
51
+
52
+ describe '#initialize' do
53
+ it 'should raise an error if :api_key is missing' do
54
+ expect{
55
+ message.delivery_method MultiMail::Sender::Postmark
56
+ message.deliver
57
+ }.to raise_error(ArgumentError, "Missing required arguments: api_key")
58
+ end
59
+
60
+ it 'should raise an error if :api_key is nil' do
61
+ expect{
62
+ message.delivery_method MultiMail::Sender::Postmark, :api_key => nil
63
+ message.deliver
64
+ }.to raise_error(ArgumentError, "Missing required arguments: api_key")
65
+ end
66
+
67
+ it 'should raise an error if :api_key is invalid' do
68
+ expect{
69
+ message.delivery_method MultiMail::Sender::Postmark, :api_key => 'xxx'
70
+ message.deliver
71
+ }.to raise_error(MultiMail::InvalidAPIKey, 'Bad or missing server or user API token.')
72
+ end
73
+ end
74
+
75
+ describe '#deliver' do
76
+ before :all do
77
+ Mail.defaults do
78
+ delivery_method MultiMail::Sender::Postmark, :api_key => 'POSTMARK_API_TEST'
79
+ end
80
+ end
81
+
82
+ it 'should send a message' do
83
+ message.deliver.should == message
84
+ message['Message-ID'].should_not be_nil # postmark gem
85
+ end
86
+ end
87
+
88
+ describe '#deliver!' do
89
+ before :all do
90
+ Mail.defaults do
91
+ delivery_method MultiMail::Sender::Postmark, :api_key => 'POSTMARK_API_TEST', :return_response => true
92
+ end
93
+ end
94
+
95
+ it 'should send a message' do
96
+ result = message.deliver!
97
+ result.size.should == 10 # string keys are deprecated
98
+
99
+ Time.parse(result[:submitted_at]).should be_within(1).of(Time.now)
100
+ result[:to].should == "bar@example.com"
101
+ result[:message_id].should match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
102
+ result[:error_code].should == 0
103
+ result[:message].should == 'Test job accepted'
104
+ end
105
+
106
+ it 'should not send a message without a From header' do
107
+ expect{message_without_from.deliver!}.to raise_error(MultiMail::MissingSender, "Invalid 'From' value.")
108
+ end
109
+
110
+ it 'should not send a message without a To header' do
111
+ expect{message_without_to.deliver!}.to raise_error(MultiMail::MissingRecipients, 'Zero recipients specified')
112
+ end
113
+
114
+ it 'should not send a message without a body' do
115
+ expect{message_without_body.deliver!}.to raise_error(MultiMail::MissingBody, 'Provide either email TextBody or HtmlBody or both.')
116
+ end
117
+ end
118
+ end
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe MultiMail::Receiver::Base do
4
4
  let :klass do
5
- Class.new(MultiMail::Service) do
5
+ Class.new do
6
6
  include MultiMail::Receiver::Base
7
7
 
8
8
  def valid?(params)
@@ -36,29 +36,36 @@ describe MultiMail::Receiver::Base do
36
36
  end
37
37
 
38
38
  describe '#parse' do
39
+ let :expected do
40
+ {'foo' => '1', 'bar' => ['1', '1']}
41
+ end
42
+
39
43
  it 'should parse JSON' do
40
- klass.parse('{"foo":1,"bar":1,"bar":1}').should == {'foo' => 1, 'bar' => 1}
44
+ klass.parse('{"foo":"1","bar":["1","1"]}').should == expected
41
45
  end
42
46
 
43
47
  it 'should parse raw POST data' do
44
- klass.parse('foo=1&bar=1&bar=1').should == {'foo' => '1', 'bar' => ['1', '1']}
48
+ klass.parse('foo=1&bar=1&bar=1').should == expected
45
49
  end
46
50
 
47
51
  it 'should accept an array' do
48
- klass.parse([['foo', 1], ['bar', [1, 1]]]).should == {'foo' => 1, 'bar' => [1, 1]}
49
- end
50
-
51
- it 'should accept a Rack::Request object' do
52
- klass.parse(Rack::Request.new(Rack::MockRequest.env_for('/?foo=1&bar[]=1&bar[]=1'))).should == {'foo' => '1', 'bar' => ['1', '1']}
52
+ klass.parse([['foo', '1'], ['bar', ['1', '1']]]).should == expected
53
53
  end
54
54
 
55
55
  it 'should pass-through a hash' do
56
- klass.parse('foo' => 1).should == {'foo' => 1}
56
+ klass.parse({'foo' => '1', 'bar' => ['1', '1']}).should == expected
57
57
  end
58
58
 
59
59
  it 'should raise an error if the argument is invalid' do
60
60
  expect{ klass.parse(1) }.to raise_error(ArgumentError, "Can't handle Fixnum input")
61
61
  end
62
+
63
+ it 'should accept a Rack::Request object' do
64
+ params = klass.parse(Rack::Request.new(Rack::MockRequest.env_for('/?foo=1&bar[]=1&bar[]=1')))
65
+ params['env'].should be_a(Hash)
66
+ params.delete('env')
67
+ params.should == expected
68
+ end
62
69
  end
63
70
 
64
71
  describe '#add_file_arguments' do
@@ -2,20 +2,34 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe MultiMail::Sender::Base do
4
4
  let :klass do
5
- Class.new(MultiMail::Service) do
5
+ Class.new do
6
6
  include MultiMail::Sender::Base
7
7
 
8
- def valid?(params)
9
- params['foo'] == 1
10
- end
11
-
12
- def transform(params)
13
- [Mail.new]
14
- end
8
+ requires :foo
15
9
  end
16
10
  end
17
11
 
18
- let :service do
19
- klass.new
12
+ describe '#initialize' do
13
+ it 'should symbolize keys' do
14
+ instance = klass.new('foo' => 1, :bar => 2, nil => 3, true => 4, false => 5, 6 => 6)
15
+ instance.settings.should == {
16
+ :foo => 1,
17
+ :bar => 2,
18
+ nil => 3,
19
+ true => 4,
20
+ false => 5,
21
+ 6 => 6,
22
+ }
23
+ end
24
+
25
+ it 'should have default settings' do
26
+ sender = klass.new(:foo => '')
27
+ sender.tracking.should == {}
28
+ end
29
+
30
+ it 'should assign custom settings' do
31
+ sender = klass.new(:foo => '', :track => {:opens => true})
32
+ sender.tracking.should == {:opens => true}
33
+ end
20
34
  end
21
35
  end
@@ -0,0 +1,265 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'multi_mail/sendgrid/message'
3
+
4
+ describe MultiMail::Message::SendGrid do
5
+ let :message do
6
+ headers = {
7
+ 'X-Autoreply' => true,
8
+ 'X-Precedence' => 'auto_reply',
9
+ 'X-Numeric' => 42,
10
+ 'Delivered-To' => 'Autoresponder',
11
+ }
12
+
13
+ MultiMail::Message::SendGrid.new do
14
+ date Time.at(946702800)
15
+ headers headers
16
+ from %("John Doe" <foo@example.com>)
17
+ to [%("Jane Doe" <bar@example.com>), '<baz@example.com>']
18
+ cc 'cc@example.com'
19
+ bcc 'bcc@example.com'
20
+ reply_to 'noreply@example.com'
21
+ subject 'test'
22
+
23
+ text_part do
24
+ body 'hello'
25
+ end
26
+
27
+ html_part do
28
+ content_type 'text/html; charset=UTF-8'
29
+ body '<p>hello</p>'
30
+ end
31
+
32
+ add_file empty_gif_path
33
+ add_file :filename => 'foo.txt', :content => 'hello world'
34
+ end
35
+ end
36
+
37
+ let :message_without_names do
38
+ MultiMail::Message::SendGrid.new do
39
+ from 'foo@example.com'
40
+ to ['bar@example.com', 'baz@example.com']
41
+ subject 'test'
42
+ body 'hello'
43
+ end
44
+ end
45
+
46
+ let :message_with_known_extension do
47
+ MultiMail::Message::SendGrid.new do
48
+ from 'foo@example.com'
49
+ to 'bar@example.com'
50
+ subject 'test'
51
+ body 'hello'
52
+ add_file :filename => 'xxx.mov', :content => ''
53
+ end
54
+ end
55
+
56
+ let :message_with_unknown_extension do
57
+ MultiMail::Message::SendGrid.new do
58
+ from 'foo@example.com'
59
+ to 'bar@example.com'
60
+ subject 'test'
61
+ body 'hello'
62
+ add_file :filename => 'xxx.xxx', :content => ''
63
+ end
64
+ end
65
+
66
+ let :message_without_extension do
67
+ MultiMail::Message::SendGrid.new do
68
+ from 'foo@example.com'
69
+ to 'bar@example.com'
70
+ subject 'test'
71
+ body 'hello'
72
+ add_file :filename => 'xxx', :content => ''
73
+ end
74
+ end
75
+
76
+ let :message_with_empty_file do
77
+ MultiMail::Message::SendGrid.new do
78
+ from 'foo@example.com'
79
+ to 'bar@example.com'
80
+ subject 'test'
81
+ body 'hello'
82
+ add_file :filename => '', :content => ''
83
+ end
84
+ end
85
+
86
+ let :message_with_empty_headers do
87
+ headers = {
88
+ 'X-Autoreply' => nil,
89
+ }
90
+
91
+ MultiMail::Message::SendGrid.new do
92
+ headers headers
93
+ from 'foo@example.com'
94
+ to 'bar@example.com'
95
+ reply_to nil
96
+ subject 'test'
97
+ body 'hello'
98
+ end
99
+ end
100
+
101
+ let :message_without_html_body do
102
+ MultiMail::Message::SendGrid.new do
103
+ from 'foo@example.com'
104
+ to 'bar@example.com'
105
+ subject 'test'
106
+ body 'hello'
107
+ end
108
+ end
109
+
110
+ let :message_without_text_body do
111
+ MultiMail::Message::SendGrid.new do
112
+ from 'foo@example.com'
113
+ to 'bar@example.com'
114
+ subject 'test'
115
+ body '<p>hello</p>'
116
+ content_type 'text/html; charset=UTF-8'
117
+ end
118
+ end
119
+
120
+ let :empty_message do
121
+ MultiMail::Message::SendGrid.new
122
+ end
123
+
124
+ describe '#sendgrid_files' do
125
+ it 'should return the attachments' do
126
+ files = message.sendgrid_files
127
+ files['empty.gif'].content_type.should == 'image/gif; filename=empty.gif'
128
+ files['empty.gif'].original_filename.should == 'empty.gif'
129
+ files['empty.gif'].read.should == File.open(empty_gif_path, 'r:binary'){|f| f.read}
130
+ files['foo.txt'].content_type.should == 'text/plain; filename=foo.txt'
131
+ files['foo.txt'].original_filename.should == 'foo.txt'
132
+ files['foo.txt'].read.should == 'hello world'
133
+ files.size.should == 2
134
+ end
135
+
136
+ it 'should return an attachment with an known extension' do
137
+ files = message_with_known_extension.sendgrid_files
138
+ files['xxx.mov'].content_type.should == 'video/quicktime; filename=xxx.mov'
139
+ files['xxx.mov'].original_filename.should == 'xxx.mov'
140
+ files['xxx.mov'].read.should == ''
141
+ files.size.should == 1
142
+ end
143
+
144
+ it 'should return an attachment with an unknown extension' do
145
+ files = message_with_unknown_extension.sendgrid_files
146
+ files['xxx.xxx'].content_type.should == 'text/plain'
147
+ files['xxx.xxx'].original_filename.should == 'xxx.xxx'
148
+ files['xxx.xxx'].read.should == ''
149
+ files.size.should == 1
150
+ end
151
+
152
+ it 'should return an attachment without an extension' do
153
+ files = message_without_extension.sendgrid_files
154
+ files['xxx'].content_type.should == 'text/plain'
155
+ files['xxx'].original_filename.should == 'xxx'
156
+ files['xxx'].read.should == ''
157
+ files.size.should == 1
158
+ end
159
+
160
+ it 'should return an empty array if the attachment is blank' do
161
+ message_with_empty_file.sendgrid_files.should == {}
162
+ end
163
+
164
+ it 'should return an empty array' do
165
+ empty_message.sendgrid_files.should == {}
166
+ end
167
+ end
168
+
169
+ describe '#sendgrid_content' do
170
+ it 'should return the content IDs' do
171
+ content = message.sendgrid_content
172
+ content.should == {'empty.gif' => 'empty.gif'}
173
+ end
174
+
175
+ it 'should return an empty array if the attachment is blank' do
176
+ message_with_empty_file.sendgrid_content.should == {}
177
+ end
178
+
179
+ it 'should return an empty array' do
180
+ empty_message.sendgrid_content.should == {}
181
+ end
182
+ end
183
+
184
+ describe '#sendgrid_headers' do
185
+ it 'should return the headers' do
186
+ headers = message.sendgrid_headers
187
+ headers['Cc'].should == 'cc@example.com'
188
+ headers['X-Autoreply'].should == 'true'
189
+ headers['X-Precedence'].should == 'auto_reply'
190
+ headers['X-Numeric'].should == '42'
191
+ headers['Delivered-To'].should == 'Autoresponder'
192
+
193
+ headers['Content-Type'].should match(%r{\Amultipart/alternative; boundary=--==_mimepart_[0-9a-f_]+\z})
194
+
195
+ headers.size.should == 6
196
+ end
197
+
198
+ it 'should return empty X-* headers' do
199
+ headers = message_with_empty_headers.sendgrid_headers
200
+ headers.should == {'X-Autoreply' => ''}
201
+ end
202
+
203
+ it 'should return an empty hash' do
204
+ empty_message.sendgrid_headers.should == {}
205
+ end
206
+ end
207
+
208
+ describe '#to_sendgrid_hash' do
209
+ it 'should return the message as SendGrid parameters' do
210
+ hash = message.to_sendgrid_hash
211
+
212
+ hash[:to].should == ['bar@example.com', 'baz@example.com']
213
+ hash[:toname].should == ['Jane Doe', nil]
214
+ hash[:subject].should == 'test'
215
+ hash[:text].should == 'hello'
216
+ hash[:html].should == '<p>hello</p>'
217
+ hash[:from].should == 'foo@example.com'
218
+ hash[:bcc].should == ['bcc@example.com']
219
+ hash[:fromname].should == 'John Doe'
220
+ hash[:replyto].should == 'noreply@example.com'
221
+ hash[:content].should == {'empty.gif' => 'empty.gif'}
222
+
223
+ hash[:headers].should match(/"Cc":"cc@example.com"/)
224
+ hash[:headers].should match(%r{"Content-Type":"multipart/alternative; boundary=--==_mimepart_[0-9a-f_]+"})
225
+ hash[:headers].should match(/"X-Autoreply":"true"/)
226
+ hash[:headers].should match(/"X-Precedence":"auto_reply"/)
227
+ hash[:headers].should match(/"X-Numeric":"42"/)
228
+ hash[:headers].should match(/"Delivered-To":"Autoresponder"/)
229
+ Time.parse(hash[:'date']).should be_within(1).of(Time.at(946702800))
230
+
231
+ hash[:files]['empty.gif'].content_type.should == 'image/gif; filename=empty.gif'
232
+ hash[:files]['empty.gif'].original_filename.should == 'empty.gif'
233
+ hash[:files]['empty.gif'].read.should == File.open(empty_gif_path, 'r:binary'){|f| f.read}
234
+ hash[:files]['foo.txt'].content_type.should == 'text/plain; filename=foo.txt'
235
+ hash[:files]['foo.txt'].original_filename.should == 'foo.txt'
236
+ hash[:files]['foo.txt'].read.should == 'hello world'
237
+ hash[:files].size.should == 2
238
+
239
+ hash.size.should == 13
240
+ end
241
+
242
+ it 'should convert the message without a text body' do
243
+ message_without_text_body.to_sendgrid_hash.should == {
244
+ :to => ['bar@example.com'],
245
+ :subject => 'test',
246
+ :html => '<p>hello</p>',
247
+ :from => 'foo@example.com',
248
+ :headers => %({"Content-Type":"text/html; charset=UTF-8"}),
249
+ }
250
+ end
251
+
252
+ it 'should convert the message without an HTML body' do
253
+ message_without_html_body.to_sendgrid_hash.should == {
254
+ :to => ['bar@example.com'],
255
+ :subject => 'test',
256
+ :text => 'hello',
257
+ :from => 'foo@example.com',
258
+ }
259
+ end
260
+
261
+ it 'should convert an empty message' do
262
+ empty_message.to_sendgrid_hash.should == {}
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,77 @@
1
+ # coding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ require 'multi_mail/sendgrid/receiver'
4
+
5
+ describe MultiMail::Receiver::SendGrid do
6
+ context 'after initialization' do
7
+ let :service do
8
+ MultiMail::Receiver.new(:provider => :sendgrid)
9
+ end
10
+
11
+ def params(fixture, encoding = 'UTF-8')
12
+ MultiMail::Receiver::SendGrid.parse(response('sendgrid', fixture, false, encoding))
13
+ end
14
+
15
+ describe '#transform' do
16
+ it 'should return a mail message' do
17
+ messages = service.transform(params('valid'))
18
+ messages.size.should == 1
19
+ message = messages[0]
20
+
21
+ # Headers
22
+ message.date.should == DateTime.parse('Mon, 15 Apr 2013 20:20:12 -0400')
23
+ message.from.should == ['james@opennorth.ca']
24
+ message.to.should == ['foo+bar@parolecitoyenne.com']
25
+ message.subject.should == 'Test'
26
+
27
+ # Body
28
+ message.multipart?.should == true
29
+ # @note SendGrid adds additional HTML parts as attachments, which is
30
+ # sensible, but it does not match the behavior of other email APIs.
31
+ message.parts.size.should == 6
32
+ message.parts[0].content_type.should == 'text/plain'
33
+ message.parts[1].content_type.should == 'text/html; charset=UTF-8'
34
+ message.parts[0].body.decoded.should == "bold text\n\n\n\nsome more bold text\n\n\n\nsome italic text\n\n> multiline\n> quoted\n> text\n\n\n--\nSignature block"
35
+ # @note Due to a SendGrid bug, the HTML part is missing content.
36
+ message.parts[1].body.decoded.should == %(<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><b>bold text</b><div><br></div><div></div></body></html>)
37
+
38
+ # HTML attachments
39
+ message.parts[3].content_type.should == 'text/html; filename=msg-12415-313.html'
40
+ message.parts[5].content_type.should == 'text/html; filename=msg-12415-314.html'
41
+ message.parts[3].body.decoded.should == %(<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><head></head><br><div></div><div><br></div><div><b>some more bold text</b></div><div><b><br></b></div><div><b></b></div></body></html>)
42
+ message.parts[5].body.decoded.should == %(<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><b></b></div><div><b><span class="Apple-style-span" style="font-weight: normal; "><br></span></b></div><div><b><span class="Apple-style-span" style="font-weight: normal; "><i>some italic text</i></span></b></div><div><b><span class="Apple-style-span" style="font-weight: normal; "><br></span></b></div><div><blockquote type="cite">multiline</blockquote><blockquote type="cite">quoted</blockquote><blockquote type="cite">text</blockquote></div><div><br></div><div>--</div><div>Signature block</div></body></html>)
43
+
44
+ # Attachments
45
+ attachment0 = message.attachments.find{|attachment| attachment.filename == 'foo.txt'}
46
+ attachment1 = message.attachments.find{|attachment| attachment.filename == 'bar.txt'}
47
+ attachment0.read.should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
48
+ attachment1.read.should == "Nam accumsan euismod eros et rhoncus.\n"
49
+
50
+ # Extra SendGrid parameters
51
+ message['dkim'].value.should == 'none'
52
+ message['SPF'].value.should == 'pass'
53
+ message['spam_report'].value.should == "Spam detection software, running on the system \"mx3.sendgrid.net\", has\r\nidentified this incoming email as possible spam. The original message\r\nhas been attached to this so you can view it (if it isn't spam) or label\r\nsimilar future email. If you have any questions, see\r\nthe administrator of that system for details.\r\n\r\nContent preview: bold text some more bold text some italic text [...] \r\n\r\nContent analysis details: (-2.6 points, 5.0 required)\r\n\r\n pts rule name description\r\n---- ---------------------- --------------------------------------------------\r\n-0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low\r\n trust\r\n [209.85.223.172 listed in list.dnswl.org]\r\n-1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1%\r\n [score: 0.0000]\r\n 0.0 HTML_MESSAGE BODY: HTML included in message\r\n\r\n"
54
+ message['spam_score'].value.should == '-2.599'
55
+ end
56
+
57
+ # No postbin is capable of handling mixed encodings, and most fail to even
58
+ # display the request. http://postbin.hackyon.com/ works best, but we
59
+ # still need to hand-edit the response.
60
+ it 'should respect encodings' do
61
+ service.transform(params('encoding', 'WINDOWS-1252'))[0].text_part.decoded.should == 'World €'
62
+ end
63
+ end
64
+
65
+ describe '#spam?' do
66
+ it 'should return true if the response is spam' do
67
+ message = service.transform(params('spam'))[0]
68
+ service.spam?(message).should == true
69
+ end
70
+
71
+ it 'should return false if the response is ham' do
72
+ message = service.transform(params('valid'))[0]
73
+ service.spam?(message).should == false
74
+ end
75
+ end
76
+ end
77
+ end