multi_mail 0.1.3 → 0.1.4

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.
@@ -2,6 +2,8 @@ module MultiMail
2
2
  module Message
3
3
  # @see http://documentation.mailgun.com/api-sending.html
4
4
  class Mailgun < MultiMail::Message::Base
5
+ attr_accessor :stripped_text, :stripped_signature, :stripped_html, :content_id_map
6
+
5
7
  # Returns the message headers in Mailgun format.
6
8
  #
7
9
  # @return [Multimap] the message headers in Mailgun format
@@ -34,7 +34,7 @@ module MultiMail
34
34
  # Transforms the content of Mailgun's webhook into a list of messages.
35
35
  #
36
36
  # @param [Hash] params the content of Mailgun's webhook
37
- # @return [Array<Mail::Message>] messages
37
+ # @return [Array<MultiMail::Message::Mailgun>] messages
38
38
  # @see http://documentation.mailgun.net/user_manual.html#mime-messages-parameters
39
39
  # @see http://documentation.mailgun.net/user_manual.html#parsed-messages-parameters
40
40
  def transform(params)
@@ -44,7 +44,7 @@ module MultiMail
44
44
  headers = self.class.multimap(JSON.load(params['message-headers']))
45
45
  this = self
46
46
 
47
- message = Mail.new do
47
+ message = Message::Mailgun.new do
48
48
  headers headers
49
49
 
50
50
  # The following are redundant with `body-mime` in raw MIME format
@@ -78,27 +78,27 @@ module MultiMail
78
78
  end
79
79
 
80
80
  # Extra Mailgun parameters.
81
- extra = [
82
- 'stripped-text',
83
- 'stripped-signature',
84
- 'stripped-html',
85
- 'content-id-map',
86
- ]
87
-
88
- # Non-plain, non-HTML body parts.
89
- extra += params.keys.select do |key|
90
- key[/\Abody-(?!html|plain)/]
81
+ if params.key?('stripped-text') && !params['stripped-text'].empty?
82
+ message.stripped_text = params['stripped-text']
91
83
  end
92
-
93
- extra.each do |key|
94
- if params.key?(key) && !params[key].empty?
95
- message[key] = params[key]
96
- end
84
+ if params.key?('stripped-signature') && !params['stripped-signature'].empty?
85
+ message.stripped_signature = params['stripped-signature']
97
86
  end
87
+ if params.key?('stripped-html') && !params['stripped-html'].empty?
88
+ message.stripped_html = params['stripped-html']
89
+ end
90
+ if params.key?('content-id-map') && !params['content-id-map'].empty?
91
+ message.content_id_map = params['content-id-map']
92
+ end
93
+
94
+ # @todo Store non-plain, non-HTML body parts.
95
+ # params.keys.select do |key|
96
+ # key[/\Abody-(?!html|plain)/]
97
+ # end
98
98
 
99
99
  [message]
100
100
  when 'raw'
101
- message = self.class.condense(Mail.new(params['body-mime']))
101
+ message = self.class.condense(Message::Mailgun.new(Mail.new(params['body-mime'])))
102
102
  [message]
103
103
  else
104
104
  raise ArgumentError, "Can't handle Mailgun #{@http_post_format} HTTP POST format"
@@ -17,7 +17,7 @@ module MultiMail
17
17
  def initialize(options = {})
18
18
  super
19
19
  @api_key = settings.delete(:api_key)
20
- @domain = settings.delete(:domain)
20
+ @domain = settings.delete(:domain)
21
21
  end
22
22
 
23
23
  # Returns the additional parameters for the API call.
@@ -2,6 +2,8 @@ module MultiMail
2
2
  module Message
3
3
  # @see https://mandrillapp.com/api/docs/messages.ruby.html#method-send
4
4
  class Mandrill < MultiMail::Message::Base
5
+ attr_accessor :ts, :email, :dkim_signed, :dkim_valid, :spam_report_score, :spf_result
6
+
5
7
  # Returns the To header in Mandrill format.
6
8
  #
7
9
  # @return [Array<Hash>] the To header in Mandrill format
@@ -39,7 +39,7 @@ module MultiMail
39
39
  # Transforms the content of Mandrill's webhook into a list of messages.
40
40
  #
41
41
  # @param [Hash] params the content of Mandrill's webhook
42
- # @return [Array<Mail::Message>] messages
42
+ # @return [Array<MultiMail::Message::Mandrill>] messages
43
43
  # @see http://help.mandrill.com/entries/22092308-What-is-the-format-of-inbound-email-webhooks-
44
44
  def transform(params)
45
45
  # JSON is necessarily UTF-8.
@@ -52,7 +52,7 @@ module MultiMail
52
52
  headers = self.class.multimap(msg['headers'])
53
53
  this = self
54
54
 
55
- message = Mail.new do
55
+ message = Message::Mandrill.new do
56
56
  headers headers
57
57
 
58
58
  # The following are redundant with `message-headers`:
@@ -71,7 +71,7 @@ module MultiMail
71
71
  # If an email contains multiple HTML parts, Mandrill will only
72
72
  # include the first HTML part in its `html` parameter. We therefore
73
73
  # parse its `raw_msg` parameter to set the HTML part correctly.
74
- html = this.class.condense(Mail.new(msg['raw_msg'])).parts.find do |part|
74
+ html = this.class.condense(Message::Mandrill.new(Mail.new(msg['raw_msg']))).parts.find do |part|
75
75
  part.content_type == 'text/html; charset=UTF-8'
76
76
  end
77
77
 
@@ -98,12 +98,12 @@ module MultiMail
98
98
  # null according to the docs, `matched_rules` within `spam_report`,
99
99
  # and `detail` within `spf`, which is just a human-readable version of
100
100
  # `result`.
101
- message['ts'] = event['ts']
102
- message['email'] = msg['email']
103
- message['dkim-signed'] = msg['dkim']['signed'].to_s
104
- message['dkim-valid'] = msg['dkim']['valid'].to_s
105
- message['spam_report-score'] = msg['spam_report']['score']
106
- message['spf-result'] = msg['spf']['result']
101
+ message.ts = event['ts']
102
+ message.email = msg['email']
103
+ message.dkim_signed = msg['dkim']['signed']
104
+ message.dkim_valid = msg['dkim']['valid']
105
+ message.spam_report_score = msg['spam_report']['score']
106
+ message.spf_result = msg['spf']['result']
107
107
 
108
108
  message
109
109
  end
@@ -114,7 +114,7 @@ module MultiMail
114
114
  # @param [Mail::Message] message a message
115
115
  # @return [Boolean] whether the message is spam
116
116
  def spam?(message)
117
- message['spam_report-score'] && message['spam_report-score'].value.to_f > @spamassassin_threshold
117
+ message.spam_report_score > @spamassassin_threshold
118
118
  end
119
119
 
120
120
  private
@@ -6,7 +6,7 @@ module MultiMail
6
6
 
7
7
  requires :api_key
8
8
 
9
- attr_reader :api_key, :async, :ip_pool, :send_at
9
+ attr_reader :api_key, :async, :ip_pool, :send_at, :template_name, :template_content
10
10
 
11
11
  # Initializes a Mandrill outgoing email sender.
12
12
  #
@@ -16,16 +16,23 @@ module MultiMail
16
16
  # mode optimized for bulk sending
17
17
  # @option options [String] :ip_pool the name of the dedicated IP pool that
18
18
  # should be used to send the message
19
+ # @option options [String] :template_name the slug or name of a template
20
+ # that exists in the user's Mandrill account
21
+ # @option options [Array<Hash>] :template_content an array of hashes, each
22
+ # with a `"name"` key for the editable region to inject into and a
23
+ # `"content"` key for the content to inject
19
24
  # @option options [Time,String] :send_at when this message should be sent
20
25
  # @see https://mandrillapp.com/api/docs/index.ruby.html
21
26
  # @see https://mandrillapp.com/api/docs/messages.JSON.html#method-send
22
27
  def initialize(options = {})
23
28
  super
24
29
  @api_key = settings.delete(:api_key)
25
- @async = settings.delete(:async) || false
30
+ @async = settings.delete(:async) || false
26
31
  @ip_pool = settings.delete(:ip_pool)
27
32
  @send_at = settings.delete(:send_at)
28
- unless @send_at.nil? or String === @send_at
33
+ @template_name = settings.delete(:template_name)
34
+ @template_content = settings.delete(:template_content)
35
+ unless @send_at.nil? || String === @send_at
29
36
  @send_at = @send_at.utc.strftime('%Y-%m-%d %T')
30
37
  end
31
38
  end
@@ -60,15 +67,28 @@ module MultiMail
60
67
  # @see https://bitbucket.org/mailchimp/mandrill-api-ruby/src/d0950a6f9c4fac1dd2d5198a4f72c12c626ab149/lib/mandrill/api.rb?at=master#cl-738
61
68
  # @see https://bitbucket.org/mailchimp/mandrill-api-ruby/src/d0950a6f9c4fac1dd2d5198a4f72c12c626ab149/lib/mandrill.rb?at=master#cl-32
62
69
  def deliver!(mail)
70
+ @template_name = settings.delete(:template_name)
71
+ @template_content = settings.delete(:template_content)
72
+
63
73
  message = MultiMail::Message::Mandrill.new(mail).to_mandrill_hash.merge(parameters)
64
74
 
65
- response = Faraday.post('https://mandrillapp.com/api/1.0/messages/send.json', JSON.dump({
75
+ api_params = {
66
76
  :key => api_key,
67
77
  :message => message,
68
78
  :async => async,
69
79
  :ip_pool => ip_pool,
70
80
  :send_at => send_at,
71
- }))
81
+ }
82
+
83
+ if template_name
84
+ api_method = 'send-template'
85
+ api_params[:template_name] = template_name
86
+ api_params[:template_content] = template_content
87
+ else
88
+ api_method = 'send'
89
+ end
90
+
91
+ response = Faraday.post("https://mandrillapp.com/api/1.0/messages/#{api_method}.json", JSON.dump(api_params))
72
92
 
73
93
  body = JSON.load(response.body)
74
94
 
@@ -77,8 +97,10 @@ module MultiMail
77
97
  case body['name']
78
98
  when 'Invalid_Key'
79
99
  raise InvalidAPIKey, body['message']
100
+ when 'Unknown_Template'
101
+ raise InvalidTemplate, body['message']
80
102
  else
81
- raise body['message']
103
+ raise "#{body['name']}: #{body['message']}"
82
104
  end
83
105
  else
84
106
  raise body['message']
@@ -2,6 +2,8 @@ module MultiMail
2
2
  module Message
3
3
  # @see http://developer.postmarkapp.com/developer-build.html#message-format
4
4
  class Postmark < MultiMail::Message::Base
5
+ attr_accessor :mailboxhash, :messageid, :tag
6
+
5
7
  # Returns the message headers in Postmark format.
6
8
  #
7
9
  # @return [Array<Hash>] the message headers in Postmark format
@@ -4,6 +4,10 @@ module MultiMail
4
4
  class Postmark
5
5
  include MultiMail::Receiver::Base
6
6
 
7
+ # Transforms the content of Postmark's webhook into a list of messages.
8
+ #
9
+ # @param [Hash] params the content of Postmark's webhook
10
+ # @return [Array<MultiMail::Message::Postmark>] messages
7
11
  def transform(params)
8
12
  headers = Multimap.new
9
13
  params['Headers'].each do |header|
@@ -15,7 +19,7 @@ module MultiMail
15
19
  to = params['ToFull'].map{|hash| transform_address(hash)}
16
20
  cc = params['CcFull'].map{|hash| transform_address(hash)}
17
21
 
18
- message = Mail.new do
22
+ message = Message::Postmark.new do
19
23
  headers headers
20
24
  message_id params['MessageID']
21
25
 
@@ -41,10 +45,14 @@ module MultiMail
41
45
  end
42
46
 
43
47
  # Extra Postmark parameters.
44
- %w(MailboxHash MessageID Tag).each do |key|
45
- if params.key?(key) && !params[key].empty?
46
- message[key] = params[key]
47
- end
48
+ if params.key?('MailboxHash') && !params['MailboxHash'].empty?
49
+ message.mailboxhash = params['MailboxHash']
50
+ end
51
+ if params.key?('MessageID') && !params['MessageID'].empty?
52
+ message.messageid = params['MessageID']
53
+ end
54
+ if params.key?('Tag') && !params['Tag'].empty?
55
+ message.tag = params['Tag']
48
56
  end
49
57
 
50
58
  [message]
@@ -18,6 +18,28 @@ module MultiMail
18
18
  @api_key = settings.delete(:api_key)
19
19
  end
20
20
 
21
+ # Returns the additional parameters for the API call.
22
+ #
23
+ # @return [Hash] the additional parameters for the API call
24
+ def parameters
25
+ parameters = settings.dup
26
+ parameters.delete(:return_response)
27
+
28
+ if tracking.key?(:opens)
29
+ parameter = :TrackOpens
30
+ case tracking[:opens]
31
+ when true, false, nil
32
+ parameters[parameter] = tracking[:opens]
33
+ when 'yes'
34
+ parameters[parameter] = true
35
+ when 'no'
36
+ parameters[parameter] = false
37
+ end # ignore "htmlonly"
38
+ end
39
+
40
+ parameters
41
+ end
42
+
21
43
  # Delivers a message via the Postmark API.
22
44
  #
23
45
  # @param [Mail::Message] mail a message
@@ -25,8 +47,6 @@ module MultiMail
25
47
  # @see http://developer.postmarkapp.com/developer-build.html#http-response-codes
26
48
  # @see http://developer.postmarkapp.com/developer-build.html#api-error-codes
27
49
  def deliver!(mail)
28
- parameters = settings.dup
29
- parameters.delete(:return_response)
30
50
  message = MultiMail::Message::Postmark.new(mail).to_postmark_hash.merge(parameters)
31
51
 
32
52
  response = Faraday.post do |request|
@@ -2,6 +2,8 @@ module MultiMail
2
2
  module Message
3
3
  # @see http://sendgrid.com/docs/API_Reference/Web_API/mail.html
4
4
  class SendGrid < MultiMail::Message::Base
5
+ attr_accessor :dkim, :spf, :spam_report, :spam_score
6
+
5
7
  # Returns the message headers in SendGrid format.
6
8
  #
7
9
  # @return [Hash] the message headers in SendGrid format
@@ -16,7 +16,7 @@ module MultiMail
16
16
  # Transforms the content of SendGrid's webook into a list of messages.
17
17
  #
18
18
  # @param [Hash] params the content of Mandrill's webhook
19
- # @return [Array<Mail::Messages>] messages
19
+ # @return [Array<MultiMail::Message::SendGrid>] messages
20
20
  # @see http://sendgrid.com/docs/API_Reference/Webhooks/parse.html
21
21
  def transform(params)
22
22
  # Make variables available to the `encode` method.
@@ -26,7 +26,7 @@ module MultiMail
26
26
  # Mail changes `self`.
27
27
  this = self
28
28
 
29
- message = Mail.new do
29
+ message = Message::SendGrid.new do
30
30
  # SendGrid includes a `charsets` parameter, which describes the
31
31
  # encodings of the `from`, `to`, `cc` and `subject` parameters, which
32
32
  # we don't need because we parse the headers directly.
@@ -57,10 +57,11 @@ module MultiMail
57
57
  end
58
58
  end
59
59
 
60
- # Extra SendGrid parameters. Discard
61
- %w(dkim SPF spam_report spam_score).each do |key|
62
- message[key] = params[key]
63
- end
60
+ # Extra SendGrid parameters.
61
+ message.dkim = params['dkim']
62
+ message.spf = params['SPF']
63
+ message.spam_report = params['spam_report']
64
+ message.spam_score = params['spam_score']
64
65
 
65
66
  # Discard `envelope`, which contains `to` and `from`, and the
66
67
  # undocumented `attachment-info`.
@@ -72,7 +73,7 @@ module MultiMail
72
73
  # @param [Mail::Message] message a message
73
74
  # @return [Boolean] whether the message is spam
74
75
  def spam?(message)
75
- message['spam_score'] && message['spam_score'].value.to_f > @spamassassin_threshold
76
+ message.spam_score.to_f > @spamassassin_threshold
76
77
  end
77
78
 
78
79
  def encode(key)
@@ -1,3 +1,3 @@
1
1
  module MultiMail
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
data/multi_mail.gemspec CHANGED
@@ -5,9 +5,8 @@ Gem::Specification.new do |s|
5
5
  s.name = "multi_mail"
6
6
  s.version = MultiMail::VERSION
7
7
  s.platform = Gem::Platform::RUBY
8
- s.authors = ["Open North"]
9
- s.email = ["info@opennorth.ca"]
10
- s.homepage = "http://github.com/opennorth/multi_mail"
8
+ s.authors = ["James McKinney"]
9
+ s.homepage = "https://github.com/jpmckinney/multi_mail"
11
10
  s.summary = %q{Easily switch between email APIs}
12
11
  s.license = 'MIT'
13
12
 
@@ -16,20 +15,19 @@ Gem::Specification.new do |s|
16
15
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
16
  s.require_paths = ["lib"]
18
17
 
19
- s.add_runtime_dependency 'faraday', '~> 0.8.0'
20
- s.add_runtime_dependency 'mail', '~> 2.5.3' # Rails 3.2.13, less buggy than 2.4.x
21
- s.add_runtime_dependency 'rack', '~> 1.4'
18
+ s.add_runtime_dependency('faraday', '~> 0.9.0')
19
+ s.add_runtime_dependency('mail', '~> 2.5')
20
+ s.add_runtime_dependency('rack', '~> 1.5')
22
21
 
23
22
  # For testing
24
- s.add_development_dependency 'coveralls'
25
- s.add_development_dependency 'json', '~> 1.7.7' # to silence coveralls warning
26
- s.add_development_dependency 'rake'
27
- s.add_development_dependency 'rspec', '~> 2.10'
28
- s.add_development_dependency 'vcr', '~> 2.4.0'
23
+ s.add_development_dependency('coveralls')
24
+ s.add_development_dependency('rake')
25
+ s.add_development_dependency('rspec', '~> 2.10')
29
26
 
30
27
  # For Rake tasks
31
- s.add_development_dependency 'mandrill-api', '~> 1.0.35'
32
- s.add_development_dependency 'postmark'
33
- s.add_development_dependency 'rest-client', '~> 1.6.7'
34
- s.add_development_dependency 'sendgrid_webapi'
28
+ s.add_development_dependency('mandrill-api', '~> 1.0.35')
29
+ s.add_development_dependency('postmark')
30
+ s.add_development_dependency('rest-client', '~> 1.8.0')
31
+ # sendgrid_webapi 0.0.2 depends on Faraday 0.8.
32
+ # s.add_development_dependency('sendgrid_webapi', '0.0.2')
35
33
  end
@@ -63,8 +63,8 @@ describe MultiMail::Receiver::Cloudmailin do
63
63
  message.subject.should == 'Test'
64
64
 
65
65
  # Body
66
- message.multipart?.should == true
67
- message.parts.size.should == 4
66
+ message.multipart?.should == true
67
+ message.parts.size.should == 4
68
68
  text_part = message.parts.find{|part| part.content_type == 'text/plain'}
69
69
  html_part = message.parts.find{|part| part.content_type == 'text/html; charset=UTF-8'}
70
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"
@@ -92,11 +92,11 @@ describe MultiMail::Receiver::Cloudmailin do
92
92
 
93
93
  # Extra Cloudmailin parameters
94
94
  if actual_http_post_format == 'raw'
95
- message['reply_plain'].should be_nil
95
+ message.reply_plain.should be_nil
96
96
  else
97
- message['reply_plain'].value.should == "bold text\n\n\n\nsome more bold text\n\n\n\nsome italic text\n"
97
+ message.reply_plain.should == "bold text\n\n\n\nsome more bold text\n\n\n\nsome italic text\n"
98
98
  end
99
- message['spf-result'].value.should == 'pass'
99
+ message.spf_result.should == 'pass'
100
100
  end
101
101
  end
102
102
 
@@ -92,8 +92,8 @@ describe MultiMail::Receiver::Mailgun do
92
92
  message.subject.should == 'Test'
93
93
 
94
94
  # Body
95
- message.multipart?.should == true
96
- message.parts.size.should == 4
95
+ message.multipart?.should == true
96
+ message.parts.size.should == 4
97
97
  text_part = message.parts.find{|part| part.content_type == 'text/plain'}
98
98
  html_part = message.parts.find{|part| part.content_type == 'text/html; charset=UTF-8'}
99
99
  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"
@@ -110,13 +110,13 @@ describe MultiMail::Receiver::Mailgun do
110
110
  # text" but `stripped-html` doesn't. `stripped-signature` and
111
111
  # `stripped-text` use CRLF line endings.
112
112
  if actual_http_post_format == 'raw'
113
- message['stripped-text'].should be_nil
114
- message['stripped-signature'].should be_nil
115
- message['stripped-html'].should be_nil
113
+ message.stripped_text.should be_nil
114
+ message.stripped_signature.should be_nil
115
+ message.stripped_html.should be_nil
116
116
  else
117
- message['stripped-text'].value.should == "bold text\r\n\r\n\r\n\r\nsome more bold text\r\n\r\n\r\n\r\nsome italic text"
118
- message['stripped-signature'].value.should == "--\r\nSignature block"
119
- message['stripped-html'].value.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><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><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></html></html>'
117
+ message.stripped_text.should == "bold text\r\n\r\n\r\n\r\nsome more bold text\r\n\r\n\r\n\r\nsome italic text"
118
+ message.stripped_signature.should == "--\r\nSignature block"
119
+ message.stripped_html.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><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><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></html></html>'
120
120
  end
121
121
  end
122
122
  end