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
@@ -1,11 +1,10 @@
1
1
  module MultiMail
2
2
  module Receiver
3
3
  # Mailgun's incoming email receiver.
4
- class Mailgun < MultiMail::Service
4
+ class Mailgun
5
5
  include MultiMail::Receiver::Base
6
6
 
7
- requires :mailgun_api_key
8
- recognizes :http_post_format
7
+ recognizes :mailgun_api_key, :http_post_format
9
8
 
10
9
  # Initializes a Mailgun incoming email receiver.
11
10
  #
@@ -25,9 +24,11 @@ module MultiMail
25
24
  # @raise [IndexError] if the request is missing parameters
26
25
  # @see http://documentation.mailgun.net/user_manual.html#securing-webhooks
27
26
  def valid?(params)
28
- params.fetch('signature') == OpenSSL::HMAC.hexdigest(
29
- OpenSSL::Digest::Digest.new('sha256'), @mailgun_api_key,
30
- '%s%s' % [params.fetch('timestamp'), params.fetch('token')])
27
+ if @mailgun_api_key
28
+ params.fetch('signature') == signature(params)
29
+ else
30
+ super
31
+ end
31
32
  end
32
33
 
33
34
  # Transforms the content of Mailgun's webhook into a list of messages.
@@ -39,12 +40,10 @@ module MultiMail
39
40
  def transform(params)
40
41
  case @http_post_format
41
42
  when 'parsed', '', nil
42
- headers = Multimap.new
43
- JSON.parse(params['message-headers']).each do |key,value|
44
- headers[key] = value
45
- end
46
-
43
+ # Mail changes `self`.
44
+ headers = self.class.multimap(JSON.load(params['message-headers']))
47
45
  this = self
46
+
48
47
  message = Mail.new do
49
48
  headers headers
50
49
 
@@ -71,7 +70,7 @@ module MultiMail
71
70
  end
72
71
 
73
72
  if params.key?('attachment-count')
74
- 1.upto(params['attachment-count'].to_i).each do |n|
73
+ 1.upto(params['attachment-count'].to_i) do |n|
75
74
  attachment = params["attachment-#{n}"]
76
75
  add_file(this.class.add_file_arguments(attachment))
77
76
  end
@@ -99,7 +98,8 @@ module MultiMail
99
98
 
100
99
  [message]
101
100
  when 'raw'
102
- [Mail.new(params['body-mime'])]
101
+ message = self.class.condense(Mail.new(params['body-mime']))
102
+ [message]
103
103
  else
104
104
  raise ArgumentError, "Can't handle Mailgun #{@http_post_format} HTTP POST format"
105
105
  end
@@ -117,6 +117,13 @@ module MultiMail
117
117
  def spam?(message)
118
118
  message['X-Mailgun-Sflag'] && message['X-Mailgun-Sflag'].value == 'Yes'
119
119
  end
120
+
121
+ private
122
+
123
+ def signature(params)
124
+ data = "#{params.fetch('timestamp')}#{params.fetch('token')}"
125
+ OpenSSL::HMAC.hexdigest('sha256', @mailgun_api_key, data)
126
+ end
120
127
  end
121
128
  end
122
129
  end
@@ -1,13 +1,90 @@
1
+ require 'multi_mail/mailgun/message'
2
+
1
3
  module MultiMail
2
4
  module Sender
3
- class Mailgun < MultiMail::Service
5
+ # Mailgun's outgoing mail sender.
6
+ class Mailgun
4
7
  include MultiMail::Sender::Base
5
8
 
6
- #requires :
9
+ requires :api_key, :domain
10
+
11
+ attr_reader :api_key, :domain
7
12
 
13
+ # Initializes a Mailgun outgoing email sender.
14
+ #
8
15
  # @param [Hash] options required and optional arguments
16
+ # @option options [String] :api_key a Mailgun API key
9
17
  def initialize(options = {})
10
18
  super
19
+ @api_key = settings.delete(:api_key)
20
+ @domain = settings.delete(:domain)
21
+ end
22
+
23
+ # Returns the additional parameters for the API call.
24
+ #
25
+ # @return [Hash] the additional parameters for the API call
26
+ def parameters
27
+ parameters = settings.dup
28
+ parameters.delete(:return_response)
29
+
30
+ [:opens, :clicks].each do |sym|
31
+ if tracking.key?(sym)
32
+ parameter = :"o:tracking-#{sym}"
33
+ case tracking[sym]
34
+ when 'yes', 'no', 'htmlonly'
35
+ parameters[parameter] = tracking[sym]
36
+ when true
37
+ parameters[parameter] = 'yes'
38
+ when false
39
+ parameters[parameter] = 'no'
40
+ end # ignore nil
41
+ end
42
+ end
43
+
44
+ parameters
45
+ end
46
+
47
+ # Delivers a message via the Mailgun API.
48
+ #
49
+ # @param [Mail::Message] mail a message
50
+ def deliver!(mail)
51
+ message = MultiMail::Message::Mailgun.new(mail).to_mailgun_hash.merge(parameters)
52
+
53
+ connection = Faraday.new do |conn|
54
+ conn.basic_auth 'api', api_key
55
+ conn.request :multipart
56
+ conn.request :url_encoded
57
+ conn.adapter Faraday.default_adapter
58
+ end
59
+
60
+ response = connection.post("https://api.mailgun.net/v2/#{domain}/messages", message)
61
+
62
+ case response.status
63
+ when 401
64
+ raise InvalidAPIKey, response.body
65
+ when 400
66
+ body = JSON.load(response.body)
67
+ case body['message']
68
+ when "'from' parameter is missing"
69
+ raise MissingSender, body['message']
70
+ when "'to' parameter is missing"
71
+ raise MissingRecipients, body['message']
72
+ when "Need at least one of 'text' or 'html' parameters specified"
73
+ raise MissingBody, body['message']
74
+ else
75
+ raise InvalidMessage, body['message']
76
+ end
77
+ when 200
78
+ body = JSON.load(response.body)
79
+ else
80
+ raise response.body
81
+ end
82
+
83
+ if settings[:return_response]
84
+ body
85
+ else
86
+ self
87
+ end
11
88
  end
12
89
  end
13
90
  end
@@ -0,0 +1,74 @@
1
+ module MultiMail
2
+ module Message
3
+ # @see https://mandrillapp.com/api/docs/messages.ruby.html#method-send
4
+ class Mandrill < MultiMail::Message::Base
5
+ # Returns the To header in Mandrill format.
6
+ #
7
+ # @return [Array<Hash>] the To header in Mandrill format
8
+ def mandrill_to
9
+ if to
10
+ to.each_with_index.map do |value,index|
11
+ {
12
+ 'email' => value,
13
+ 'name' => self[:to].display_names[index]
14
+ }
15
+ end
16
+ else
17
+ []
18
+ end
19
+ end
20
+
21
+ # Returns the message headers in Mandrill format.
22
+ #
23
+ # @return [Hash] the message headers in Mandrill format
24
+ def mandrill_headers
25
+ headers = {}
26
+ header_fields.each do |field|
27
+ key = field.name.downcase
28
+ # Mandrill only allows Reply-To and X-* headers currently.
29
+ # https://mandrillapp.com/api/docs/messages.ruby.html
30
+ if key == 'reply-to' || key.start_with?('x-')
31
+ headers[field.name] = field.value
32
+ end
33
+ end
34
+ headers
35
+ end
36
+
37
+ # Returns the message's attachments in Mandrill format.
38
+ #
39
+ # @return [Array<Faraday::UploadIO>] the attachments in Mandrill format
40
+ def mandrill_attachments
41
+ attachments.map do |attachment|
42
+ {
43
+ 'type' => attachment.content_type,
44
+ 'name' => attachment.filename,
45
+ 'content' => Base64.encode64(attachment.body.decoded)
46
+ }
47
+ end
48
+ end
49
+
50
+ # Returns the message as parameters to POST to Mandrill.
51
+ #
52
+ # @return [Hash] the message as parameters to POST to Mandrill
53
+ def to_mandrill_hash
54
+ images, attachments = mandrill_attachments.partition do |attachment|
55
+ attachment['type'].start_with?('image/')
56
+ end
57
+
58
+ hash = {
59
+ 'html' => body_html,
60
+ 'text' => body_text,
61
+ 'subject' => subject,
62
+ 'from_email' => from && from.first,
63
+ 'from_name' => from && self[:from].display_names.first,
64
+ 'to' => mandrill_to,
65
+ 'headers' => mandrill_headers,
66
+ 'attachments' => attachments,
67
+ 'images' => images,
68
+ }
69
+
70
+ normalize(hash)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -5,10 +5,10 @@ module MultiMail
5
5
  # Mandrill uses an HTTP header to ensure a request originates from Mandrill.
6
6
  #
7
7
  # @see http://help.mandrill.com/entries/23704122-Authenticating-webhook-requests
8
- class Mandrill < MultiMail::Service
8
+ class Mandrill
9
9
  include MultiMail::Receiver::Base
10
10
 
11
- recognizes :spamassassin_threshold
11
+ recognizes :spamassassin_threshold, :mandrill_webhook_key, :mandrill_webhook_url
12
12
 
13
13
  # Initializes a Mandrill incoming email receiver.
14
14
  #
@@ -18,6 +18,22 @@ module MultiMail
18
18
  def initialize(options = {})
19
19
  super
20
20
  @spamassassin_threshold = options[:spamassassin_threshold] || 5
21
+ @mandrill_webhook_key = options[:mandrill_webhook_key]
22
+ @mandrill_webhook_url = options[:mandrill_webhook_url]
23
+ end
24
+
25
+ # Returns whether a request originates from Mandrill.
26
+ #
27
+ # @param [Hash] params the content of Mandrill's webhook
28
+ # @return [Boolean] whether the request originates from Mailgun
29
+ # @raise [IndexError] if the request is missing parameters
30
+ # @see http://help.mandrill.com/entries/23704122-Authenticating-webhook-requests
31
+ def valid?(params)
32
+ if @mandrill_webhook_url && @mandrill_webhook_key
33
+ params.fetch('env').fetch('HTTP_X_MANDRILL_SIGNATURE') == signature(params)
34
+ else
35
+ super
36
+ end
21
37
  end
22
38
 
23
39
  # Transforms the content of Mandrill's webhook into a list of messages.
@@ -27,23 +43,15 @@ module MultiMail
27
43
  # @see http://help.mandrill.com/entries/22092308-What-is-the-format-of-inbound-email-webhooks-
28
44
  def transform(params)
29
45
  # JSON is necessarily UTF-8.
30
- JSON.parse(params['mandrill_events']).select do |event|
46
+ JSON.load(params['mandrill_events']).select do |event|
31
47
  event.fetch('event') == 'inbound'
32
48
  end.map do |event|
33
49
  msg = event['msg']
34
50
 
35
- headers = Multimap.new
36
- msg['headers'].each do |key,value|
37
- if Array === value
38
- value.each do |v|
39
- headers[key] = v
40
- end
41
- else
42
- headers[key] = value
43
- end
44
- end
45
-
51
+ # Mail changes `self`.
52
+ headers = self.class.multimap(msg['headers'])
46
53
  this = self
54
+
47
55
  message = Mail.new do
48
56
  headers headers
49
57
 
@@ -88,8 +96,8 @@ module MultiMail
88
96
 
89
97
  # Extra Mandrill parameters. Discard `sender` and `tags`, which are
90
98
  # null according to the docs, `matched_rules` within `spam_report`,
91
- # `detail` within `spf`, which is just a human-readable version of
92
- # `result`, and `raw_msg`.
99
+ # and `detail` within `spf`, which is just a human-readable version of
100
+ # `result`.
93
101
  message['ts'] = event['ts']
94
102
  message['email'] = msg['email']
95
103
  message['dkim-signed'] = msg['dkim']['signed'].to_s
@@ -108,6 +116,18 @@ module MultiMail
108
116
  def spam?(message)
109
117
  message['spam_report-score'] && message['spam_report-score'].value.to_f > @spamassassin_threshold
110
118
  end
119
+
120
+ private
121
+
122
+ def signature(params)
123
+ data = @mandrill_webhook_url
124
+ params.sort.each do |key,value|
125
+ unless key == 'env'
126
+ data += "#{key}#{value}"
127
+ end
128
+ end
129
+ Base64.encode64(OpenSSL::HMAC.digest('sha1', @mandrill_webhook_key, data)).strip
130
+ end
111
131
  end
112
132
  end
113
133
  end
@@ -1,13 +1,88 @@
1
+ require 'multi_mail/mandrill/message'
2
+
1
3
  module MultiMail
2
4
  module Sender
3
- class Mandrill < MultiMail::Service
5
+ # Mandrill's outgoing mail sender.
6
+ class Mandrill
4
7
  include MultiMail::Sender::Base
5
8
 
6
- #requires :
9
+ requires :api_key
10
+
11
+ attr_reader :api_key, :async, :ip_pool, :send_at
7
12
 
13
+ # Initializes a Mandrill outgoing email sender.
14
+ #
8
15
  # @param [Hash] options required and optional arguments
16
+ # @option options [String] :api_key a Mandrill API key
17
+ # @see https://mandrillapp.com/api/docs/index.ruby.html
9
18
  def initialize(options = {})
10
19
  super
20
+ @api_key = settings.delete(:api_key)
21
+ @async = settings.delete(:async) || false
22
+ @ip_pool = settings.delete(:ip_pool)
23
+ @send_at = settings.delete(:send_at)
24
+ end
25
+
26
+ # Returns the additional parameters for the API call.
27
+ #
28
+ # @return [Hash] the additional parameters for the API call
29
+ def parameters
30
+ parameters = settings.dup
31
+ parameters.delete(:return_response)
32
+
33
+ [:opens, :clicks].each do |sym|
34
+ if tracking.key?(sym)
35
+ parameter = :"track_#{sym}"
36
+ case tracking[sym]
37
+ when true, false, nil
38
+ parameters[parameter] = tracking[sym]
39
+ when 'yes'
40
+ parameters[parameter] = true
41
+ when 'no'
42
+ parameters[parameter] = false
43
+ end # ignore "htmlonly"
44
+ end
45
+ end
46
+
47
+ parameters
48
+ end
49
+
50
+ # Delivers a message via the Mandrill API.
51
+ #
52
+ # @param [Mail::Message] mail a message
53
+ # @see https://bitbucket.org/mailchimp/mandrill-api-ruby/src/d0950a6f9c4fac1dd2d5198a4f72c12c626ab149/lib/mandrill/api.rb?at=master#cl-738
54
+ # @see https://bitbucket.org/mailchimp/mandrill-api-ruby/src/d0950a6f9c4fac1dd2d5198a4f72c12c626ab149/lib/mandrill.rb?at=master#cl-32
55
+ def deliver!(mail)
56
+ message = MultiMail::Message::Mandrill.new(mail).to_mandrill_hash.merge(parameters)
57
+
58
+ response = Faraday.post('https://mandrillapp.com/api/1.0/messages/send.json', JSON.dump({
59
+ :key => api_key,
60
+ :message => message,
61
+ :async => async,
62
+ :ip_pool => ip_pool,
63
+ :send_at => send_at,
64
+ }))
65
+
66
+ body = JSON.load(response.body)
67
+
68
+ unless response.status == 200
69
+ if body['status'] == 'error'
70
+ case body['name']
71
+ when 'Invalid_Key'
72
+ raise InvalidAPIKey, body['message']
73
+ else
74
+ raise body['message']
75
+ end
76
+ else
77
+ raise body['message']
78
+ end
79
+ end
80
+
81
+ if settings[:return_response]
82
+ body
83
+ else
84
+ self
85
+ end
11
86
  end
12
87
  end
13
88
  end
@@ -0,0 +1,40 @@
1
+ module MultiMail
2
+ module Message
3
+ class Base < Mail::Message
4
+ # @see https://github.com/wildbit/postmark-gem/blob/master/lib/postmark/message_extensions/mail.rb
5
+ def html?
6
+ !!content_type && content_type.include?('text/html')
7
+ end
8
+
9
+ def body_html
10
+ if html_part
11
+ html_part.body.decoded
12
+ elsif html?
13
+ body.decoded
14
+ end
15
+ end
16
+
17
+ def body_text
18
+ if text_part
19
+ text_part.body.decoded
20
+ elsif !html?
21
+ body.decoded
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def normalize(hash)
28
+ hash.delete_if do |_,value|
29
+ value.nil? || value.empty? || Array === value && value.all?{|v| v.nil?}
30
+ end
31
+
32
+ hash.keys.each do |key| # based on Hash#symbolize_keys! from Rails
33
+ hash[(key.to_sym rescue key) || key] = hash.delete(key)
34
+ end
35
+
36
+ hash
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,7 +1,7 @@
1
1
  module MultiMail
2
2
  module Receiver
3
3
  # Postmark's incoming email receiver.
4
- class Postmark < MultiMail::Service
4
+ class Postmark
5
5
  include MultiMail::Receiver::Base
6
6
 
7
7
  def transform(params)
@@ -1,13 +1,43 @@
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
+
1
7
  module MultiMail
2
8
  module Sender
3
- class Postmark < MultiMail::Service
9
+ # Postmark's outgoing mail sender.
10
+ class Postmark
4
11
  include MultiMail::Sender::Base
5
12
 
6
- #requires :
13
+ # @see https://github.com/wildbit/postmark-gem#communicating-with-the-api
14
+ requires :api_key
15
+
16
+ # Delivers a message via the Postmark API.
17
+ #
18
+ # @param [Mail::Message] mail a message
19
+ # @see https://github.com/wildbit/postmark-gem#using-postmark-with-the-mail-library
20
+ def deliver!(mail)
21
+ mail.delivery_method Mail::Postmark, settings
7
22
 
8
- # @param [Hash] options required and optional arguments
9
- def initialize(options = {})
10
- super
23
+ if settings[:return_response]
24
+ mail.deliver!
25
+ else
26
+ mail.deliver
27
+ end
28
+ rescue ::Postmark::InvalidApiKeyError => e
29
+ raise InvalidAPIKey, e.message
30
+ rescue ::Postmark::InvalidMessageError => e
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
38
+ else
39
+ raise InvalidMessage, e.message
40
+ end
11
41
  end
12
42
  end
13
43
  end
@@ -7,10 +7,18 @@ module MultiMail
7
7
  module Base
8
8
  def self.included(subclass)
9
9
  subclass.class_eval do
10
+ extend MultiMail::Service
10
11
  extend MultiMail::Receiver::Base::ClassMethods
11
12
  end
12
13
  end
13
14
 
15
+ # Initializes an incoming email receiver.
16
+ #
17
+ # @param [Hash] options required and optional arguments
18
+ def initialize(options = {})
19
+ self.class.validate_options(options)
20
+ end
21
+
14
22
  # Ensures a request is authentic, parses it into a params hash, and
15
23
  # transforms it into a list of messages.
16
24
  #
@@ -66,6 +74,24 @@ module MultiMail
66
74
  end
67
75
  end
68
76
 
77
+ # Converts a hash or array to a multimap.
78
+ #
79
+ # @param [Hash,Array] object a hash or array
80
+ # @return [Multimap] a multimap
81
+ def multimap(object)
82
+ multimap = Multimap.new
83
+ object.each do |key,value|
84
+ if Array === value
85
+ value.each do |v|
86
+ multimap[key] = v
87
+ end
88
+ else
89
+ multimap[key] = value
90
+ end
91
+ end
92
+ multimap
93
+ end
94
+
69
95
  # Parses raw POST data into a params hash.
70
96
  #
71
97
  # @param [String,Hash] raw raw POST data or a params hash
@@ -74,7 +100,7 @@ module MultiMail
74
100
  case raw
75
101
  when String
76
102
  begin
77
- JSON.parse(raw)
103
+ JSON.load(raw)
78
104
  rescue JSON::ParserError
79
105
  params = CGI.parse(raw)
80
106
 
@@ -107,7 +133,10 @@ module MultiMail
107
133
 
108
134
  params
109
135
  when Rack::Request
110
- raw.params
136
+ env = raw.env.dup
137
+ env.delete('rack.input')
138
+ env.delete('rack.errors')
139
+ {'env' => env}.merge(raw.params)
111
140
  when Hash
112
141
  raw
113
142
  else
@@ -14,7 +14,7 @@ module MultiMail
14
14
  #
15
15
  # @param [Hash] attributes required arguments
16
16
  # @option attributes [String,Symbol] :provider a provider
17
- # @return [MultiMail::Service] an incoming email receiver
17
+ # @return an incoming email receiver
18
18
  # @raise [ArgumentError] if the provider does not exist
19
19
  # @see Fog::Storage::new
20
20
  def self.new(attributes)
@@ -38,9 +38,6 @@ module MultiMail
38
38
  when :simple
39
39
  require 'multi_mail/simple/receiver'
40
40
  MultiMail::Receiver::Simple.new(attributes)
41
- when :mock
42
- # for testing
43
- MultiMail::Receiver::Mock.new(attributes)
44
41
  else
45
42
  raise ArgumentError.new("#{provider} is not a recognized provider")
46
43
  end
@@ -1,7 +1,29 @@
1
1
  module MultiMail
2
2
  module Sender
3
- # Abstract class for outgoing email services.
3
+ # Abstract class for outgoing email senders.
4
4
  module Base
5
+ def self.included(subclass)
6
+ subclass.class_eval do
7
+ extend MultiMail::Service
8
+ end
9
+ end
10
+
11
+ attr_reader :settings, :tracking
12
+
13
+ # Initializes an outgoing email sender.
14
+ #
15
+ # @param [Hash] options required and optional arguments
16
+ def initialize(options = {})
17
+ @settings = {}
18
+
19
+ options.keys.each do |key| # based on Hash#symbolize_keys! from Rails
20
+ settings[(key.to_sym rescue key) || key] = options[key]
21
+ end
22
+
23
+ self.class.validate_options(settings, false)
24
+
25
+ @tracking = settings.delete(:track) || {}
26
+ end
5
27
  end
6
28
  end
7
29
  end