multi_mail 0.1.0 → 0.1.1
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/README.md +57 -34
- data/bin/multi_mail_post +71 -0
- data/lib/mail_ext/message.rb +11 -0
- data/lib/multi_mail.rb +25 -8
- data/lib/multi_mail/cloudmailin/receiver.rb +24 -3
- data/lib/multi_mail/mailgun/message.rb +6 -1
- data/lib/multi_mail/mailgun/sender.rb +4 -4
- data/lib/multi_mail/mandrill/message.rb +4 -3
- data/lib/multi_mail/mandrill/sender.rb +9 -2
- data/lib/multi_mail/message/base.rb +14 -0
- data/lib/multi_mail/postmark/message.rb +74 -0
- data/lib/multi_mail/postmark/receiver.rb +2 -1
- data/lib/multi_mail/postmark/sender.rb +54 -24
- data/lib/multi_mail/sendgrid/message.rb +4 -4
- data/lib/multi_mail/sendgrid/sender.rb +2 -2
- data/lib/multi_mail/simple/receiver.rb +31 -1
- data/lib/multi_mail/version.rb +1 -1
- data/multi_mail.gemspec +2 -1
- data/spec/cloudmailin/receiver_spec.rb +89 -84
- data/spec/fixtures/cloudmailin/json/attachment_store.txt +65 -0
- data/spec/fixtures/cloudmailin/multipart/attachment_store.txt +174 -0
- data/spec/fixtures/cloudmailin/raw/attachment_store.txt +162 -0
- data/spec/fixtures/mailgun/parsed/valid.txt +107 -101
- data/spec/fixtures/simple/invalid.txt +4 -0
- data/spec/fixtures/simple/missing.txt +4 -0
- data/spec/fixtures/simple/valid.txt +1 -1
- data/spec/mail_ext/message_spec.rb +45 -0
- data/spec/mailgun/message_spec.rb +38 -8
- data/spec/mailgun/receiver_spec.rb +104 -110
- data/spec/mailgun/sender_spec.rb +13 -7
- data/spec/mandrill/message_spec.rb +25 -1
- data/spec/mandrill/receiver_spec.rb +81 -83
- data/spec/mandrill/sender_spec.rb +13 -6
- data/spec/message/base_spec.rb +33 -1
- data/spec/postmark/message_spec.rb +292 -0
- data/spec/postmark/receiver_spec.rb +46 -48
- data/spec/postmark/sender_spec.rb +10 -10
- data/spec/sendgrid/message_spec.rb +6 -1
- data/spec/sendgrid/receiver_spec.rb +56 -58
- data/spec/sendgrid/sender_spec.rb +9 -7
- data/spec/service_spec.rb +1 -1
- data/spec/simple/receiver_spec.rb +38 -25
- data/spec/spec_helper.rb +6 -8
- metadata +185 -203
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'multi_mail/mailgun/message'
|
2
|
-
|
3
1
|
module MultiMail
|
4
2
|
module Sender
|
5
3
|
# Mailgun's outgoing mail sender.
|
@@ -14,6 +12,8 @@ module MultiMail
|
|
14
12
|
#
|
15
13
|
# @param [Hash] options required and optional arguments
|
16
14
|
# @option options [String] :api_key a Mailgun API key
|
15
|
+
# @option options [String] :domain the Mailgun email domain
|
16
|
+
# @see http://documentation.mailgun.com/api-intro.html#base-url
|
17
17
|
def initialize(options = {})
|
18
18
|
super
|
19
19
|
@api_key = settings.delete(:api_key)
|
@@ -62,7 +62,7 @@ module MultiMail
|
|
62
62
|
case response.status
|
63
63
|
when 401
|
64
64
|
raise InvalidAPIKey, response.body
|
65
|
-
when 400
|
65
|
+
when 400, 404
|
66
66
|
body = JSON.load(response.body)
|
67
67
|
case body['message']
|
68
68
|
when "'from' parameter is missing"
|
@@ -72,7 +72,7 @@ module MultiMail
|
|
72
72
|
when "Need at least one of 'text' or 'html' parameters specified"
|
73
73
|
raise MissingBody, body['message']
|
74
74
|
else
|
75
|
-
raise
|
75
|
+
raise InvalidRequest, body['message']
|
76
76
|
end
|
77
77
|
when 200
|
78
78
|
body = JSON.load(response.body)
|
@@ -22,16 +22,16 @@ module MultiMail
|
|
22
22
|
#
|
23
23
|
# @return [Hash] the message headers in Mandrill format
|
24
24
|
def mandrill_headers
|
25
|
-
|
25
|
+
hash = {}
|
26
26
|
header_fields.each do |field|
|
27
27
|
key = field.name.downcase
|
28
28
|
# Mandrill only allows Reply-To and X-* headers currently.
|
29
29
|
# https://mandrillapp.com/api/docs/messages.ruby.html
|
30
30
|
if key == 'reply-to' || key.start_with?('x-')
|
31
|
-
|
31
|
+
hash[field.name] = field.value
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
hash
|
35
35
|
end
|
36
36
|
|
37
37
|
# Returns the message's attachments in Mandrill format.
|
@@ -65,6 +65,7 @@ module MultiMail
|
|
65
65
|
'headers' => mandrill_headers,
|
66
66
|
'attachments' => attachments,
|
67
67
|
'images' => images,
|
68
|
+
'tags' => tags,
|
68
69
|
}
|
69
70
|
|
70
71
|
normalize(hash)
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'multi_mail/mandrill/message'
|
2
|
-
|
3
1
|
module MultiMail
|
4
2
|
module Sender
|
5
3
|
# Mandrill's outgoing mail sender.
|
@@ -14,13 +12,22 @@ module MultiMail
|
|
14
12
|
#
|
15
13
|
# @param [Hash] options required and optional arguments
|
16
14
|
# @option options [String] :api_key a Mandrill API key
|
15
|
+
# @option options [Boolean] :async whether to enable a background sending
|
16
|
+
# mode optimized for bulk sending
|
17
|
+
# @option options [String] :ip_pool the name of the dedicated IP pool that
|
18
|
+
# should be used to send the message
|
19
|
+
# @option options [Time,String] :send_at when this message should be sent
|
17
20
|
# @see https://mandrillapp.com/api/docs/index.ruby.html
|
21
|
+
# @see https://mandrillapp.com/api/docs/messages.JSON.html#method-send
|
18
22
|
def initialize(options = {})
|
19
23
|
super
|
20
24
|
@api_key = settings.delete(:api_key)
|
21
25
|
@async = settings.delete(:async) || false
|
22
26
|
@ip_pool = settings.delete(:ip_pool)
|
23
27
|
@send_at = settings.delete(:send_at)
|
28
|
+
unless @send_at.nil? or String === @send_at
|
29
|
+
@send_at = @send_at.utc.strftime('%Y-%m-%d %T')
|
30
|
+
end
|
24
31
|
end
|
25
32
|
|
26
33
|
# Returns the additional parameters for the API call.
|
@@ -22,6 +22,20 @@ module MultiMail
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
def tags
|
26
|
+
if self['tag']
|
27
|
+
if self['tag'].respond_to?(:map)
|
28
|
+
self['tag'].map do |field|
|
29
|
+
field.value
|
30
|
+
end
|
31
|
+
else
|
32
|
+
[self['tag'].value]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
[]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
25
39
|
private
|
26
40
|
|
27
41
|
def normalize(hash)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module MultiMail
|
2
|
+
module Message
|
3
|
+
# @see http://developer.postmarkapp.com/developer-build.html#message-format
|
4
|
+
class Postmark < MultiMail::Message::Base
|
5
|
+
# Returns the message headers in Postmark format.
|
6
|
+
#
|
7
|
+
# @return [Multimap] the message headers in Postmark format
|
8
|
+
def postmark_headers
|
9
|
+
array = []
|
10
|
+
header_fields.each do |field|
|
11
|
+
key = field.name.downcase
|
12
|
+
# @see https://github.com/wildbit/postmark-gem/blob/master/lib/postmark/message_extensions/mail.rb#L74
|
13
|
+
# @see https://github.com/wildbit/postmark-gem/pull/36#issuecomment-22298955
|
14
|
+
unless %w(from to cc bcc reply-to subject tag content-type date).include?(key) || (Array === field.value && field.value.size > 1)
|
15
|
+
array << {'Name' => field.name, 'Value' => field.value}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
array
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the message's attachments in Postmark format.
|
22
|
+
#
|
23
|
+
# @return [Multimap] the attachments in Postmark format
|
24
|
+
# @see http://developer.postmarkapp.com/developer-build.html#attachments
|
25
|
+
def postmark_attachments
|
26
|
+
attachments.map do |attachment|
|
27
|
+
hash = {
|
28
|
+
'ContentType' => attachment.content_type,
|
29
|
+
'Name' => attachment.filename,
|
30
|
+
'Content' => Base64.encode64(attachment.body.decoded)
|
31
|
+
}
|
32
|
+
if attachment.content_type.start_with?('image/')
|
33
|
+
hash['ContentID'] = attachment.filename
|
34
|
+
end
|
35
|
+
hash
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the message as parameters to POST to Postmark.
|
40
|
+
#
|
41
|
+
# @return [Hash] the message as parameters to POST to Postmark
|
42
|
+
def to_postmark_hash
|
43
|
+
hash = {}
|
44
|
+
|
45
|
+
%w(from subject).each do |field|
|
46
|
+
if self[field]
|
47
|
+
hash[postmark_key(field)] = self[field].value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
%w(to cc bcc reply_to).each do |field|
|
52
|
+
if self[field]
|
53
|
+
value = self[field].value
|
54
|
+
hash[postmark_key(field)] = value.respond_to?(:join) ? value.join(', ') : value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
hash['TextBody'] = body_text
|
59
|
+
hash['HtmlBody'] = body_html
|
60
|
+
hash['Headers'] = postmark_headers
|
61
|
+
hash['Attachments'] = postmark_attachments
|
62
|
+
hash['Tag'] = tags.first
|
63
|
+
|
64
|
+
normalize(hash)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def postmark_key(string)
|
70
|
+
string.downcase.split(/[_-]/).map(&:capitalize).join
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -1,42 +1,72 @@
|
|
1
|
-
begin
|
2
|
-
require 'postmark'
|
3
|
-
rescue LoadError
|
4
|
-
raise 'The postmark gem is not available. In order to use the Postmark sender, you must: gem install postmark'
|
5
|
-
end
|
6
|
-
|
7
1
|
module MultiMail
|
8
2
|
module Sender
|
9
3
|
# Postmark's outgoing mail sender.
|
10
4
|
class Postmark
|
11
5
|
include MultiMail::Sender::Base
|
12
6
|
|
13
|
-
# @see https://github.com/wildbit/postmark-gem#communicating-with-the-api
|
14
7
|
requires :api_key
|
15
8
|
|
9
|
+
attr_reader :api_key
|
10
|
+
|
11
|
+
# Initializes a Postmark outgoing email sender.
|
12
|
+
#
|
13
|
+
# @param [Hash] options required and optional arguments
|
14
|
+
# @option options [String] :api_key a Postmark API key
|
15
|
+
# @see http://developer.postmarkapp.com/developer-build.html#authentication-headers
|
16
|
+
def initialize(options = {})
|
17
|
+
super
|
18
|
+
@api_key = settings.delete(:api_key)
|
19
|
+
end
|
20
|
+
|
16
21
|
# Delivers a message via the Postmark API.
|
17
22
|
#
|
18
23
|
# @param [Mail::Message] mail a message
|
19
|
-
# @see
|
24
|
+
# @see http://developer.postmarkapp.com/developer-build.html
|
25
|
+
# @see http://developer.postmarkapp.com/developer-build.html#http-response-codes
|
26
|
+
# @see http://developer.postmarkapp.com/developer-build.html#api-error-codes
|
20
27
|
def deliver!(mail)
|
21
|
-
|
28
|
+
parameters = settings.dup
|
29
|
+
parameters.delete(:return_response)
|
30
|
+
message = MultiMail::Message::Postmark.new(mail).to_postmark_hash.merge(parameters)
|
22
31
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
32
|
+
response = Faraday.post do |request|
|
33
|
+
request.url 'https://api.postmarkapp.com/email'
|
34
|
+
request.headers['Accept'] = 'application/json'
|
35
|
+
request.headers['Content-Type'] = 'application/json'
|
36
|
+
request.headers['X-Postmark-Server-Token'] = @api_key
|
37
|
+
request.body = JSON.dump(message)
|
38
|
+
end
|
39
|
+
|
40
|
+
body = JSON.load(response.body)
|
41
|
+
|
42
|
+
unless response.status == 200
|
43
|
+
case body['ErrorCode']
|
44
|
+
when 0
|
45
|
+
raise InvalidAPIKey, body['Message']
|
46
|
+
when 300
|
47
|
+
case body['Message']
|
48
|
+
when "Header 'Content-Type' not allowed."
|
49
|
+
raise InvalidHeader, body['Message']
|
50
|
+
when "Header 'Date' not allowed."
|
51
|
+
raise InvalidHeader, body['Message']
|
52
|
+
when "Invalid 'From' value."
|
53
|
+
raise MissingSender, body['Message']
|
54
|
+
when 'Zero recipients specified'
|
55
|
+
raise MissingRecipients, body['Message']
|
56
|
+
when 'Provide either email TextBody or HtmlBody or both.'
|
57
|
+
raise MissingBody, body['Message']
|
58
|
+
else
|
59
|
+
raise InvalidMessage, body['Message']
|
60
|
+
end
|
61
|
+
else
|
62
|
+
raise InvalidRequest, body['Message']
|
63
|
+
end
|
27
64
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
case e.message
|
32
|
-
when "Invalid 'From' value."
|
33
|
-
raise MissingSender, e.message
|
34
|
-
when 'Zero recipients specified'
|
35
|
-
raise MissingRecipients, e.message
|
36
|
-
when 'Provide either email TextBody or HtmlBody or both.'
|
37
|
-
raise MissingBody, e.message
|
65
|
+
|
66
|
+
if settings[:return_response]
|
67
|
+
body
|
38
68
|
else
|
39
|
-
|
69
|
+
self
|
40
70
|
end
|
41
71
|
end
|
42
72
|
end
|
@@ -6,15 +6,15 @@ module MultiMail
|
|
6
6
|
#
|
7
7
|
# @return [Hash] the message headers in SendGrid format
|
8
8
|
def sendgrid_headers
|
9
|
-
|
9
|
+
hash = {}
|
10
10
|
header_fields.each do |field|
|
11
11
|
key = field.name.downcase
|
12
|
-
unless %w(to subject from bcc reply-to date
|
12
|
+
unless %w(to subject from bcc reply-to date).include?(key)
|
13
13
|
# The JSON must not contain integers.
|
14
|
-
|
14
|
+
hash[field.name] = field.value.to_s
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
hash
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns the message's attachments in SendGrid format.
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'multi_mail/sendgrid/message'
|
2
|
-
|
3
1
|
module MultiMail
|
4
2
|
module Sender
|
5
3
|
# SendGrid's outgoing mail sender.
|
@@ -14,6 +12,8 @@ module MultiMail
|
|
14
12
|
# @param [Hash] options required and optional arguments
|
15
13
|
# @option options [String] :api_user a SendGrid API user
|
16
14
|
# @option options [String] :api_key a SendGrid API key
|
15
|
+
# @option options [Hash,String] the X-SMTPAPI SendGrid header
|
16
|
+
# @see http://sendgrid.com/docs/API_Reference/SMTP_API/index.html
|
17
17
|
def initialize(options = {})
|
18
18
|
super
|
19
19
|
if Hash === settings[:'x-smtpapi']
|
@@ -1,8 +1,33 @@
|
|
1
1
|
module MultiMail
|
2
2
|
module Receiver
|
3
|
+
# A simple incoming email receiver.
|
3
4
|
class Simple
|
4
5
|
include MultiMail::Receiver::Base
|
5
6
|
|
7
|
+
recognizes :secret
|
8
|
+
|
9
|
+
# Initializes a simple incoming email receiver.
|
10
|
+
#
|
11
|
+
# @param [Hash] options required and optional arguments
|
12
|
+
# @option options [String] :secret a secret key
|
13
|
+
def initialize(options = {})
|
14
|
+
super
|
15
|
+
@secret = options[:secret]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns whether a request is authentic.
|
19
|
+
#
|
20
|
+
# @param [Hash] params the content of the webhook
|
21
|
+
# @return [Boolean] whether the request is authentic
|
22
|
+
# @raise [IndexError] if the request is missing parameters
|
23
|
+
def valid?(params)
|
24
|
+
if @secret
|
25
|
+
params.fetch('signature') == signature(params)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
6
31
|
# Expects a raw email message parsable by the Mail gem.
|
7
32
|
#
|
8
33
|
# @param [Hash] params the content of the webhook
|
@@ -10,6 +35,11 @@ module MultiMail
|
|
10
35
|
def transform(params)
|
11
36
|
[Mail.new(params)]
|
12
37
|
end
|
38
|
+
|
39
|
+
def signature(params)
|
40
|
+
data = "#{params.fetch('timestamp')}#{params.fetch('token')}"
|
41
|
+
OpenSSL::HMAC.hexdigest('sha256', @secret, data)
|
42
|
+
end
|
13
43
|
end
|
14
44
|
end
|
15
|
-
end
|
45
|
+
end
|
data/lib/multi_mail/version.rb
CHANGED
data/multi_mail.gemspec
CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ["info@opennorth.ca"]
|
10
10
|
s.homepage = "http://github.com/opennorth/multi_mail"
|
11
11
|
s.summary = %q{Easily switch between email APIs}
|
12
|
+
s.license = 'MIT'
|
12
13
|
|
13
14
|
s.files = `git ls-files`.split("\n")
|
14
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -25,7 +26,7 @@ Gem::Specification.new do |s|
|
|
25
26
|
s.add_development_dependency 'json', '~> 1.7.7' # to silence coveralls warning
|
26
27
|
s.add_development_dependency 'rake'
|
27
28
|
s.add_development_dependency 'rspec', '~> 2.10'
|
28
|
-
s.add_development_dependency 'vcr', '~> 2.0'
|
29
|
+
s.add_development_dependency 'vcr', '~> 2.4.0'
|
29
30
|
|
30
31
|
# For Rake tasks
|
31
32
|
s.add_development_dependency 'mandrill-api', '~> 1.0.35'
|
@@ -2,108 +2,113 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
2
|
require 'multi_mail/cloudmailin/receiver'
|
3
3
|
|
4
4
|
describe MultiMail::Receiver::Cloudmailin do
|
5
|
-
context '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
5
|
+
context 'with invalid HTTP POST format' do
|
6
|
+
let :service do
|
7
|
+
MultiMail::Receiver.new({
|
8
|
+
:provider => :cloudmailin,
|
9
|
+
:http_post_format => 'invalid',
|
10
|
+
})
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
13
|
+
describe '#transform' do
|
14
|
+
it 'should raise an error if :http_post_format is invalid' do
|
15
|
+
expect{ service.transform({}) }.to raise_error(ArgumentError)
|
18
16
|
end
|
19
17
|
end
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
[false, true].each do |action_dispatch|
|
21
|
+
let :action_dispatch do
|
22
|
+
action_dispatch
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
['raw', 'json', 'multipart', '', nil].each do |http_post_format|
|
26
|
+
context "with #{http_post_format.inspect} format and #{action_dispatch ? 'ActionDispatch' : 'Rack'}" do
|
27
|
+
let :actual_http_post_format do
|
28
|
+
http_post_format.to_s.empty? ? 'raw' : http_post_format
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
31
|
+
let :service do
|
32
|
+
MultiMail::Receiver.new({
|
33
|
+
:provider => :cloudmailin,
|
34
|
+
:http_post_format => http_post_format,
|
35
|
+
})
|
36
|
+
end
|
37
|
+
|
38
|
+
def params(fixture)
|
39
|
+
MultiMail::Receiver::Cloudmailin.parse(response("cloudmailin/#{actual_http_post_format}", fixture, action_dispatch))
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#transform' do
|
43
|
+
it 'should return a mail message' do
|
44
|
+
helper(service.transform(params('valid')))
|
34
45
|
end
|
35
46
|
|
36
|
-
|
37
|
-
MultiMail::Receiver.new({
|
47
|
+
it 'should return a mail message with URL attachments' do
|
48
|
+
helper(MultiMail::Receiver.new({
|
38
49
|
:provider => :cloudmailin,
|
39
50
|
:http_post_format => http_post_format,
|
40
|
-
|
51
|
+
:attachment_store => true,
|
52
|
+
}).transform(params('attachment_store')), true)
|
41
53
|
end
|
42
54
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
55
|
+
def helper(messages, attachment_store = false)
|
56
|
+
messages.size.should == 1
|
57
|
+
message = messages[0]
|
58
|
+
|
59
|
+
# Headers
|
60
|
+
message.date.should == DateTime.parse('Mon, 15 Apr 2013 20:20:12 -04:00')
|
61
|
+
message.from.should == ['james@opennorth.ca']
|
62
|
+
message.to.should == ['5dae6f85cd65d30d384a@cloudmailin.net']
|
63
|
+
message.subject.should == 'Test'
|
46
64
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
message.multipart?.should == true
|
61
|
-
message.parts.size.should == 4
|
62
|
-
text_part = message.parts.find{|part| part.content_type == 'text/plain'}
|
63
|
-
html_part = message.parts.find{|part| part.content_type == 'text/html; charset=UTF-8'}
|
64
|
-
text_part.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"
|
65
|
-
|
66
|
-
# @note Due to a Cloudmailin bug, the HTML part is missing content
|
67
|
-
# unless you use the "raw" HTTP POST format.
|
68
|
-
if actual_http_post_format == 'raw'
|
69
|
-
html_part.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><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><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>)
|
70
|
-
else
|
71
|
-
html_part.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>)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Attachments
|
75
|
-
attachment0 = message.attachments.find{|attachment| attachment.filename == 'foo.txt'}
|
76
|
-
attachment1 = message.attachments.find{|attachment| attachment.filename == 'bar.txt'}
|
77
|
-
# @note Cloudmailin removes the newline at the end of the file,
|
78
|
-
# unless you use the "raw" HTTP POST format.
|
79
|
-
if actual_http_post_format == 'raw'
|
80
|
-
attachment0.read.should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
|
81
|
-
attachment1.read.should == "Nam accumsan euismod eros et rhoncus.\n"
|
82
|
-
else
|
83
|
-
attachment0.read.should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
|
84
|
-
attachment1.read.should == "Nam accumsan euismod eros et rhoncus."
|
85
|
-
end
|
86
|
-
|
87
|
-
# Extra Cloudmailin parameters
|
88
|
-
if actual_http_post_format == 'raw'
|
89
|
-
message['reply_plain'].should be_nil
|
90
|
-
else
|
91
|
-
message['reply_plain'].value.should == "bold text\n\n\n\nsome more bold text\n\n\n\nsome italic text\n"
|
92
|
-
end
|
93
|
-
message['spf-result'].value.should == 'pass'
|
65
|
+
# Body
|
66
|
+
message.multipart?.should == true
|
67
|
+
message.parts.size.should == 4
|
68
|
+
text_part = message.parts.find{|part| part.content_type == 'text/plain'}
|
69
|
+
html_part = message.parts.find{|part| part.content_type == 'text/html; charset=UTF-8'}
|
70
|
+
text_part.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"
|
71
|
+
|
72
|
+
# @note Due to a Cloudmailin bug, the HTML part is missing content
|
73
|
+
# unless you use the "raw" HTTP POST format or URL attachments.
|
74
|
+
if actual_http_post_format == 'raw' || attachment_store
|
75
|
+
html_part.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><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><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>)
|
76
|
+
else
|
77
|
+
html_part.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>)
|
94
78
|
end
|
95
|
-
end
|
96
79
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
80
|
+
# Attachments
|
81
|
+
attachment0 = message.attachments.find{|attachment| attachment.filename == 'foo.txt'}
|
82
|
+
attachment1 = message.attachments.find{|attachment| attachment.filename == 'bar.txt'}
|
83
|
+
# @note Cloudmailin removes the newline at the end of the file,
|
84
|
+
# unless you use the "raw" HTTP POST format or URL attachments.
|
85
|
+
if actual_http_post_format == 'raw' || attachment_store
|
86
|
+
attachment0.read.should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
|
87
|
+
attachment1.read.should == "Nam accumsan euismod eros et rhoncus.\n"
|
88
|
+
else
|
89
|
+
attachment0.read.should == "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
|
90
|
+
attachment1.read.should == "Nam accumsan euismod eros et rhoncus."
|
101
91
|
end
|
102
92
|
|
103
|
-
|
104
|
-
|
105
|
-
|
93
|
+
# Extra Cloudmailin parameters
|
94
|
+
if actual_http_post_format == 'raw'
|
95
|
+
message['reply_plain'].should be_nil
|
96
|
+
else
|
97
|
+
message['reply_plain'].value.should == "bold text\n\n\n\nsome more bold text\n\n\n\nsome italic text\n"
|
106
98
|
end
|
99
|
+
message['spf-result'].value.should == 'pass'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#spam?' do
|
104
|
+
it 'should return true if the response is spam' do
|
105
|
+
message = service.transform(params('spam'))[0]
|
106
|
+
service.spam?(message).should == true
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should return false if the response is ham' do
|
110
|
+
message = service.transform(params('valid'))[0]
|
111
|
+
service.spam?(message).should == false
|
107
112
|
end
|
108
113
|
end
|
109
114
|
end
|