multi_mail 0.0.2 → 0.1.0
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.
- data/.gitignore +2 -1
- data/.travis.yml +10 -0
- data/README.md +283 -59
- data/Rakefile +38 -19
- data/lib/multi_mail/cloudmailin/receiver.rb +3 -13
- data/lib/multi_mail/mailgun/message.rb +67 -0
- data/lib/multi_mail/mailgun/receiver.rb +20 -13
- data/lib/multi_mail/mailgun/sender.rb +79 -2
- data/lib/multi_mail/mandrill/message.rb +74 -0
- data/lib/multi_mail/mandrill/receiver.rb +36 -16
- data/lib/multi_mail/mandrill/sender.rb +77 -2
- data/lib/multi_mail/message/base.rb +40 -0
- data/lib/multi_mail/postmark/receiver.rb +1 -1
- data/lib/multi_mail/postmark/sender.rb +35 -5
- data/lib/multi_mail/receiver/base.rb +31 -2
- data/lib/multi_mail/receiver.rb +1 -4
- data/lib/multi_mail/sender/base.rb +23 -1
- data/lib/multi_mail/sendgrid/message.rb +74 -0
- data/lib/multi_mail/sendgrid/receiver.rb +72 -23
- data/lib/multi_mail/sendgrid/sender.rb +63 -2
- data/lib/multi_mail/service.rb +48 -56
- data/lib/multi_mail/simple/receiver.rb +4 -4
- data/lib/multi_mail/version.rb +1 -1
- data/lib/multi_mail.rb +16 -1
- data/multi_mail.gemspec +4 -1
- data/spec/fixtures/empty.gif +0 -0
- data/spec/fixtures/mailgun/raw/invalid.txt +13 -0
- data/spec/fixtures/mailgun/raw/missing.txt +13 -0
- data/spec/fixtures/mailgun/raw/spam.txt +13 -0
- data/spec/fixtures/mailgun/raw/valid.txt +13 -0
- data/spec/fixtures/mandrill/invalid.txt +15 -0
- data/spec/fixtures/mandrill/missing.txt +14 -0
- data/spec/fixtures/mandrill/multiple.txt +15 -0
- data/spec/fixtures/mandrill/valid.txt +10 -5
- data/spec/fixtures/postmark/valid.txt +13 -13
- data/spec/fixtures/sendgrid/encoding.txt +90 -0
- data/spec/fixtures/sendgrid/spam.txt +94 -0
- data/spec/fixtures/sendgrid/valid.txt +136 -0
- data/spec/mailgun/message_spec.rb +251 -0
- data/spec/mailgun/receiver_spec.rb +35 -20
- data/spec/mailgun/sender_spec.rb +175 -0
- data/spec/mandrill/message_spec.rb +305 -0
- data/spec/mandrill/receiver_spec.rb +90 -46
- data/spec/mandrill/sender_spec.rb +138 -0
- data/spec/message/base_spec.rb +81 -0
- data/spec/postmark/receiver_spec.rb +4 -4
- data/spec/postmark/sender_spec.rb +118 -0
- data/spec/receiver/base_spec.rb +16 -9
- data/spec/sender/base_spec.rb +24 -10
- data/spec/sendgrid/message_spec.rb +265 -0
- data/spec/sendgrid/receiver_spec.rb +77 -0
- data/spec/sendgrid/sender_spec.rb +140 -0
- data/spec/service_spec.rb +18 -1
- data/spec/simple/receiver_spec.rb +1 -1
- data/spec/spec_helper.rb +46 -4
- metadata +226 -143
- data/lib/multi_mail/sender.rb +0 -46
- data/lib/multi_mail/simple/sender.rb +0 -14
- data/spec/sender_spec.rb +0 -13
- 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
|
4
|
+
class Mailgun
|
5
5
|
include MultiMail::Receiver::Base
|
6
6
|
|
7
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
43
|
-
JSON.
|
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)
|
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
|
-
|
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
|
-
|
5
|
+
# Mailgun's outgoing mail sender.
|
6
|
+
class Mailgun
|
4
7
|
include MultiMail::Sender::Base
|
5
8
|
|
6
|
-
|
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
|
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.
|
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
|
-
|
36
|
-
msg['headers']
|
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
|
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
|
-
|
5
|
+
# Mandrill's outgoing mail sender.
|
6
|
+
class Mandrill
|
4
7
|
include MultiMail::Sender::Base
|
5
8
|
|
6
|
-
|
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,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
|
-
|
9
|
+
# Postmark's outgoing mail sender.
|
10
|
+
class Postmark
|
4
11
|
include MultiMail::Sender::Base
|
5
12
|
|
6
|
-
#
|
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
|
-
|
9
|
-
|
10
|
-
|
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.
|
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.
|
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
|
data/lib/multi_mail/receiver.rb
CHANGED
@@ -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
|
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
|
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
|