multi_mail 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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