multi_mail 0.0.1 → 0.0.2
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/.travis.yml +4 -0
- data/.yardopts +4 -0
- data/Gemfile +1 -1
- data/README.md +107 -12
- data/Rakefile +75 -52
- data/lib/multi_mail/cloudmailin/receiver.rb +100 -0
- data/lib/multi_mail/mailgun/receiver.rb +74 -36
- data/lib/multi_mail/mailgun/sender.rb +14 -0
- data/lib/multi_mail/mandrill/receiver.rb +77 -35
- data/lib/multi_mail/mandrill/sender.rb +14 -0
- data/lib/multi_mail/postmark/receiver.rb +68 -0
- data/lib/multi_mail/postmark/sender.rb +14 -0
- data/lib/multi_mail/receiver/base.rb +125 -8
- data/lib/multi_mail/receiver.rb +10 -4
- data/lib/multi_mail/sender/base.rb +7 -0
- data/lib/multi_mail/sender.rb +10 -4
- data/lib/multi_mail/sendgrid/receiver.rb +42 -0
- data/lib/multi_mail/sendgrid/sender.rb +11 -0
- data/lib/multi_mail/service.rb +15 -4
- data/lib/multi_mail/simple/receiver.rb +15 -0
- data/lib/multi_mail/simple/sender.rb +14 -0
- data/lib/multi_mail/version.rb +1 -1
- data/lib/multi_mail.rb +71 -3
- data/multi_mail.gemspec +12 -5
- data/spec/cloudmailin/receiver_spec.rb +112 -0
- data/spec/fixtures/cloudmailin/json/spam.txt +59 -0
- data/spec/fixtures/cloudmailin/json/valid.txt +59 -0
- data/spec/fixtures/cloudmailin/multipart/spam.txt +135 -0
- data/spec/fixtures/cloudmailin/multipart/valid.txt +135 -0
- data/spec/fixtures/cloudmailin/raw/spam.txt +137 -0
- data/spec/fixtures/cloudmailin/raw/valid.txt +137 -0
- data/spec/fixtures/mailgun/parsed/invalid.txt +8 -0
- data/spec/fixtures/mailgun/parsed/missing.txt +8 -0
- data/spec/fixtures/mailgun/parsed/spam.txt +8 -0
- data/spec/fixtures/mailgun/parsed/valid.txt +187 -0
- data/spec/fixtures/mandrill/spam.txt +9 -0
- data/spec/fixtures/mandrill/valid.txt +10 -0
- data/spec/fixtures/multipart.txt +99 -0
- data/spec/fixtures/postmark/spam.txt +83 -0
- data/spec/fixtures/postmark/valid.txt +92 -0
- data/spec/fixtures/simple/valid.txt +4 -0
- data/spec/mailgun/receiver_spec.rb +105 -50
- data/spec/mailgun/sender_spec.rb +0 -0
- data/spec/mandrill/receiver_spec.rb +35 -35
- data/spec/mandrill/sender_spec.rb +0 -0
- data/spec/multi_mail_spec.rb +63 -0
- data/spec/postmark/receiver_spec.rb +60 -0
- data/spec/postmark/sender_spec.rb +0 -0
- data/spec/receiver/base_spec.rb +73 -8
- data/spec/sender/base_spec.rb +21 -0
- data/spec/service_spec.rb +2 -2
- data/spec/simple/receiver_spec.rb +36 -0
- data/spec/simple/sender_spec.rb +0 -0
- data/spec/spec_helper.rb +123 -10
- metadata +141 -21
- data/spec/fixtures/mailgun/invalid.txt +0 -8
- data/spec/fixtures/mailgun/missing.txt +0 -8
- data/spec/fixtures/mailgun/spam.txt +0 -8
- data/spec/fixtures/mailgun/valid.txt +0 -8
@@ -1,71 +1,113 @@
|
|
1
1
|
module MultiMail
|
2
2
|
module Receiver
|
3
|
+
# Mandrill's incoming email receiver.
|
4
|
+
#
|
5
|
+
# Mandrill uses an HTTP header to ensure a request originates from Mandrill.
|
6
|
+
#
|
7
|
+
# @see http://help.mandrill.com/entries/23704122-Authenticating-webhook-requests
|
3
8
|
class Mandrill < MultiMail::Service
|
4
9
|
include MultiMail::Receiver::Base
|
5
10
|
|
6
|
-
|
11
|
+
recognizes :spamassassin_threshold
|
7
12
|
|
13
|
+
# Initializes a Mandrill incoming email receiver.
|
14
|
+
#
|
8
15
|
# @param [Hash] options required and optional arguments
|
9
|
-
# @option
|
16
|
+
# @option option [Float] :spamassassin_threshold the SpamAssassin score
|
17
|
+
# needed to flag a message as spam
|
10
18
|
def initialize(options = {})
|
11
19
|
super
|
12
|
-
@
|
20
|
+
@spamassassin_threshold = options[:spamassassin_threshold] || 5
|
13
21
|
end
|
14
22
|
|
23
|
+
# Transforms the content of Mandrill's webhook into a list of messages.
|
24
|
+
#
|
15
25
|
# @param [Hash] params the content of Mandrill's webhook
|
16
|
-
# @return [
|
17
|
-
|
18
|
-
|
26
|
+
# @return [Array<Mail::Message>] messages
|
27
|
+
# @see http://help.mandrill.com/entries/22092308-What-is-the-format-of-inbound-email-webhooks-
|
28
|
+
def transform(params)
|
29
|
+
# JSON is necessarily UTF-8.
|
30
|
+
JSON.parse(params['mandrill_events']).select do |event|
|
19
31
|
event.fetch('event') == 'inbound'
|
20
|
-
end
|
21
|
-
|
32
|
+
end.map do |event|
|
33
|
+
msg = event['msg']
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
28
45
|
|
29
|
-
|
30
|
-
# @return [Array<Mail::Message>] messages
|
31
|
-
# @todo parse attachments properly
|
32
|
-
def transform(params)
|
33
|
-
JSON.parse(params['mandrill_events']).map do |event|
|
46
|
+
this = self
|
34
47
|
message = Mail.new do
|
35
|
-
headers
|
48
|
+
headers headers
|
36
49
|
|
37
50
|
# The following are redundant with `message-headers`:
|
38
51
|
#
|
39
|
-
# address = Mail::Address.new
|
40
|
-
# address.display_name =
|
52
|
+
# address = Mail::Address.new(msg['from_email'])
|
53
|
+
# address.display_name = msg['from_name']
|
41
54
|
#
|
42
55
|
# from address.format
|
43
|
-
# to
|
44
|
-
# subject
|
56
|
+
# to msg['to'].flatten.compact
|
57
|
+
# subject msg['subject']
|
45
58
|
|
46
59
|
text_part do
|
47
|
-
body
|
60
|
+
body msg['text']
|
48
61
|
end
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
|
63
|
+
# If an email contains multiple HTML parts, Mandrill will only
|
64
|
+
# include the first HTML part in its `html` parameter. We therefore
|
65
|
+
# parse its `raw_msg` parameter to set the HTML part correctly.
|
66
|
+
html = this.class.condense(Mail.new(msg['raw_msg'])).parts.find do |part|
|
67
|
+
part.content_type == 'text/html; charset=UTF-8'
|
53
68
|
end
|
54
|
-
end
|
55
69
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
70
|
+
if html
|
71
|
+
html_part do
|
72
|
+
content_type 'text/html; charset=UTF-8'
|
73
|
+
body html.body.decoded
|
74
|
+
end
|
75
|
+
elsif msg.key?('html')
|
76
|
+
html_part do
|
77
|
+
content_type 'text/html; charset=UTF-8'
|
78
|
+
body msg['html']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if msg.key?('attachments')
|
83
|
+
msg['attachments'].each do |_,attachment|
|
84
|
+
add_file(:filename => attachment['name'], :content => attachment['content'])
|
85
|
+
end
|
63
86
|
end
|
64
87
|
end
|
65
88
|
|
89
|
+
# Extra Mandrill parameters. Discard `sender` and `tags`, which are
|
90
|
+
# 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`.
|
93
|
+
message['ts'] = event['ts']
|
94
|
+
message['email'] = msg['email']
|
95
|
+
message['dkim-signed'] = msg['dkim']['signed'].to_s
|
96
|
+
message['dkim-valid'] = msg['dkim']['valid'].to_s
|
97
|
+
message['spam_report-score'] = msg['spam_report']['score']
|
98
|
+
message['spf-result'] = msg['spf']['result']
|
99
|
+
|
66
100
|
message
|
67
101
|
end
|
68
102
|
end
|
103
|
+
|
104
|
+
# Returns whether a message is spam.
|
105
|
+
#
|
106
|
+
# @param [Mail::Message] message a message
|
107
|
+
# @return [Boolean] whether the message is spam
|
108
|
+
def spam?(message)
|
109
|
+
message['spam_report-score'] && message['spam_report-score'].value.to_f > @spamassassin_threshold
|
110
|
+
end
|
69
111
|
end
|
70
112
|
end
|
71
113
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module MultiMail
|
2
|
+
module Receiver
|
3
|
+
# Postmark's incoming email receiver.
|
4
|
+
class Postmark < MultiMail::Service
|
5
|
+
include MultiMail::Receiver::Base
|
6
|
+
|
7
|
+
def transform(params)
|
8
|
+
headers = Multimap.new
|
9
|
+
params['Headers'].each do |header|
|
10
|
+
headers[header['Name']] = header['Value']
|
11
|
+
end
|
12
|
+
|
13
|
+
# Due to scoping issues, we can't call `transform_address` within `Mail.new`.
|
14
|
+
from = transform_address(params['FromFull'])
|
15
|
+
to = params['ToFull'].map{|hash| transform_address(hash)}
|
16
|
+
cc = params['CcFull'].map{|hash| transform_address(hash)}
|
17
|
+
|
18
|
+
message = Mail.new do
|
19
|
+
headers headers
|
20
|
+
|
21
|
+
from from
|
22
|
+
to to
|
23
|
+
cc cc
|
24
|
+
reply_to params['ReplyTo']
|
25
|
+
subject params['Subject']
|
26
|
+
date params['Date']
|
27
|
+
|
28
|
+
text_part do
|
29
|
+
body params['TextBody']
|
30
|
+
end
|
31
|
+
|
32
|
+
html_part do
|
33
|
+
content_type 'text/html; charset=UTF-8'
|
34
|
+
body CGI.unescapeHTML(params['HtmlBody'])
|
35
|
+
end
|
36
|
+
|
37
|
+
params['Attachments'].each do |attachment|
|
38
|
+
add_file(:filename => attachment['Name'], :content => Base64.decode64(attachment['Content']))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Extra Postmark parameters.
|
43
|
+
%w(MailboxHash MessageID Tag).each do |key|
|
44
|
+
if params.key?(key) && !params[key].empty?
|
45
|
+
message[key] = params[key]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
[message]
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param [Mail::Message] message a message
|
53
|
+
# @return [Boolean] whether the message is spam
|
54
|
+
# @see http://developer.postmarkapp.com/developer-inbound-parse.html#spam
|
55
|
+
def spam?(message)
|
56
|
+
message['X-Spam-Status'].value == 'Yes'
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def transform_address(hash)
|
62
|
+
address = Mail::Address.new(hash['Email'])
|
63
|
+
address.display_name = hash['Name']
|
64
|
+
address.to_s
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module MultiMail
|
2
2
|
module Receiver
|
3
|
-
# Abstract class for incoming email
|
3
|
+
# Abstract class for incoming email receivers.
|
4
4
|
#
|
5
5
|
# The `transform` instance method must be implemented in sub-classes. The
|
6
6
|
# `valid?` and `spam?` instance methods may be implemented in sub-classes.
|
@@ -11,30 +11,39 @@ module MultiMail
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
#
|
14
|
+
# Ensures a request is authentic, parses it into a params hash, and
|
15
|
+
# transforms it into a list of messages.
|
16
|
+
#
|
17
|
+
# @param [String,Array,Hash,Rack::Request] raw raw POST data or a params hash
|
15
18
|
# @return [Array<Mail::Message>] messages
|
16
|
-
# @
|
19
|
+
# @raise [ForgedRequest] if the request is not authentic
|
17
20
|
def process(raw)
|
18
|
-
params = self.class.parse
|
19
|
-
if valid?
|
20
|
-
transform
|
21
|
+
params = self.class.parse(raw)
|
22
|
+
if valid?(params)
|
23
|
+
transform(params)
|
21
24
|
else
|
22
25
|
raise ForgedRequest
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
29
|
+
# Returns whether a request is authentic.
|
30
|
+
#
|
26
31
|
# @param [Hash] params the content of the provider's webhook
|
27
32
|
# @return [Boolean] whether the request is authentic
|
28
33
|
def valid?(params)
|
29
34
|
true
|
30
35
|
end
|
31
36
|
|
37
|
+
# Transforms the content of a provider's webhook into a list of messages.
|
38
|
+
#
|
32
39
|
# @param [Hash] params the content of the provider's webhook
|
33
40
|
# @return [Array<Mail::Message>] messages
|
34
41
|
def transform(params)
|
35
42
|
raise NotImplementedError
|
36
43
|
end
|
37
44
|
|
45
|
+
# Returns whether a message is spam.
|
46
|
+
#
|
38
47
|
# @param [Mail::Message] message a message
|
39
48
|
# @return [Boolean] whether the message is spam
|
40
49
|
def spam?(message)
|
@@ -42,23 +51,131 @@ module MultiMail
|
|
42
51
|
end
|
43
52
|
|
44
53
|
module ClassMethods
|
54
|
+
# ActionDispatch::Http::Request subclasses Rack::Request and turns
|
55
|
+
# attachment hashes into instances of ActionDispatch::Http::UploadedFile
|
56
|
+
# in Rails 3 and 4 and instances of ActionController::UploadedFile in
|
57
|
+
# Rails 2.3, both of which have the same interface.
|
58
|
+
#
|
59
|
+
# @param [ActionDispatch::Http::UploadedFile,ActionController::UploadedFile,Hash] attachment an attachment
|
60
|
+
# @return [Hash] arguments for `Mail::Message#add_file`
|
61
|
+
def add_file_arguments(attachment)
|
62
|
+
if Hash === attachment
|
63
|
+
{:filename => attachment[:filename], :content => attachment[:tempfile].read}
|
64
|
+
else
|
65
|
+
{:filename => attachment.original_filename, :content => attachment.read}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Parses raw POST data into a params hash.
|
70
|
+
#
|
45
71
|
# @param [String,Hash] raw raw POST data or a params hash
|
72
|
+
# @raise [ArgumentError] if the argument is not a string or a hash
|
46
73
|
def parse(raw)
|
47
74
|
case raw
|
48
75
|
when String
|
49
|
-
|
50
|
-
|
76
|
+
begin
|
77
|
+
JSON.parse(raw)
|
78
|
+
rescue JSON::ParserError
|
79
|
+
params = CGI.parse(raw)
|
80
|
+
|
81
|
+
# Flatten the parameters.
|
82
|
+
params.each do |key,value|
|
83
|
+
if Array === value && value.size == 1
|
84
|
+
params[key] = value.first
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
params
|
89
|
+
end
|
90
|
+
when Array
|
91
|
+
params = {}
|
92
|
+
|
93
|
+
# Collect the values for each key.
|
94
|
+
map = Multimap.new
|
95
|
+
raw.each do |key,value|
|
96
|
+
map[key] = value
|
97
|
+
end
|
98
|
+
|
99
|
+
# Flatten the parameters.
|
100
|
+
map.each do |key,value|
|
51
101
|
if Array === value && value.size == 1
|
52
102
|
params[key] = value.first
|
103
|
+
else
|
104
|
+
params[key] = value
|
53
105
|
end
|
54
106
|
end
|
107
|
+
|
55
108
|
params
|
109
|
+
when Rack::Request
|
110
|
+
raw.params
|
56
111
|
when Hash
|
57
112
|
raw
|
58
113
|
else
|
59
114
|
raise ArgumentError, "Can't handle #{raw.class.name} input"
|
60
115
|
end
|
61
116
|
end
|
117
|
+
|
118
|
+
# Condenses a message's HTML parts to a single HTML part.
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# flat = self.class.condense(message.dup)
|
122
|
+
#
|
123
|
+
# @param [Mail::Message] message a message with zero or more HTML parts
|
124
|
+
# @return [Mail::Message] the message with a single HTML part
|
125
|
+
def condense(message)
|
126
|
+
if message.multipart? && message.parts.any?(&:multipart?)
|
127
|
+
# Get the message parts as a flat array.
|
128
|
+
result = flatten(Mail.new, message.parts.dup)
|
129
|
+
|
130
|
+
# Rebuild the message's parts.
|
131
|
+
message.parts.clear
|
132
|
+
|
133
|
+
# Merge non-attachments with the same content type.
|
134
|
+
(result.parts - result.attachments).group_by(&:content_type).each do |content_type,group|
|
135
|
+
body = group.map{|part| part.body.decoded}.join
|
136
|
+
|
137
|
+
# Make content types match across all APIs.
|
138
|
+
if content_type == 'text/plain; charset=us-ascii'
|
139
|
+
# `text/plain; charset=us-ascii` is the default content type.
|
140
|
+
content_type = 'text/plain'
|
141
|
+
elsif content_type == 'text/html; charset=us-ascii'
|
142
|
+
content_type = 'text/html; charset=UTF-8'
|
143
|
+
body = body.encode('UTF-8') if body.respond_to?(:encode)
|
144
|
+
end
|
145
|
+
|
146
|
+
message.parts << Mail::Part.new({
|
147
|
+
:content_type => content_type,
|
148
|
+
:body => body,
|
149
|
+
})
|
150
|
+
end
|
151
|
+
|
152
|
+
# Add attachments last.
|
153
|
+
result.attachments.each do |part|
|
154
|
+
message.parts << part
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
message
|
159
|
+
end
|
160
|
+
|
161
|
+
# Flattens a hierarchy of message parts.
|
162
|
+
#
|
163
|
+
# @example
|
164
|
+
# flat = self.class.flatten(Mail.new, parts.dup)
|
165
|
+
#
|
166
|
+
# @param [Mail::Message] message a message
|
167
|
+
# @param [Mail::PartsList] parts parts to add to the message
|
168
|
+
# @return [Mail::Message] the message with all the parts
|
169
|
+
def flatten(message, parts)
|
170
|
+
parts.each do |part|
|
171
|
+
if part.multipart?
|
172
|
+
flatten(message, part.parts)
|
173
|
+
else
|
174
|
+
message.parts << part
|
175
|
+
end
|
176
|
+
end
|
177
|
+
message
|
178
|
+
end
|
62
179
|
end
|
63
180
|
end
|
64
181
|
end
|
data/lib/multi_mail/receiver.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module MultiMail
|
2
|
+
# Endpoint for initializing different incoming email receivers.
|
3
|
+
#
|
2
4
|
# @see http://rdoc.info/gems/fog/Fog/Storage
|
3
5
|
module Receiver
|
4
|
-
|
5
|
-
|
6
|
+
# Initializes an incoming email receiver.
|
7
|
+
#
|
6
8
|
# @example
|
7
9
|
# require 'multi_mail'
|
8
10
|
# service = MultiMail::Receiver.new({
|
@@ -11,8 +13,9 @@ module MultiMail
|
|
11
13
|
# })
|
12
14
|
#
|
13
15
|
# @param [Hash] attributes required arguments
|
14
|
-
# @option
|
15
|
-
# @
|
16
|
+
# @option attributes [String,Symbol] :provider a provider
|
17
|
+
# @return [MultiMail::Service] an incoming email receiver
|
18
|
+
# @raise [ArgumentError] if the provider does not exist
|
16
19
|
# @see Fog::Storage::new
|
17
20
|
def self.new(attributes)
|
18
21
|
attributes = attributes.dup # prevent delete from having side effects
|
@@ -32,6 +35,9 @@ module MultiMail
|
|
32
35
|
when :sendgrid
|
33
36
|
require 'multi_mail/sendgrid/receiver'
|
34
37
|
MultiMail::Receiver::SendGrid.new(attributes)
|
38
|
+
when :simple
|
39
|
+
require 'multi_mail/simple/receiver'
|
40
|
+
MultiMail::Receiver::Simple.new(attributes)
|
35
41
|
when :mock
|
36
42
|
# for testing
|
37
43
|
MultiMail::Receiver::Mock.new(attributes)
|
data/lib/multi_mail/sender.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module MultiMail
|
2
|
+
# Endpoint for initializing different outgoing email senders.
|
3
|
+
#
|
2
4
|
# @see http://rdoc.info/gems/fog/Fog/Storage
|
3
5
|
module Sender
|
4
|
-
|
5
|
-
|
6
|
+
# Initializers an outgoing email sender.
|
7
|
+
#
|
6
8
|
# @example
|
7
9
|
# require 'multi_mail'
|
8
10
|
# service = MultiMail::Sender.new({
|
@@ -11,8 +13,9 @@ module MultiMail
|
|
11
13
|
# })
|
12
14
|
#
|
13
15
|
# @param [Hash] attributes required arguments
|
14
|
-
# @option
|
15
|
-
# @
|
16
|
+
# @option attributes [String,Symbol] :provider a provider
|
17
|
+
# @return [MultiMail::Service] an outgoing email sender
|
18
|
+
# @raise [ArgumentError] if the provider does not exist
|
16
19
|
# @see Fog::Storage::new
|
17
20
|
def self.new(attributes)
|
18
21
|
attributes = attributes.dup # prevent delete from having side effects
|
@@ -29,6 +32,9 @@ module MultiMail
|
|
29
32
|
when :sendgrid
|
30
33
|
require 'multi_mail/sendgrid/sender'
|
31
34
|
MultiMail::Sender::SendGrid.new(attributes)
|
35
|
+
when :simple
|
36
|
+
require 'multi_mail/simple/sender'
|
37
|
+
MultiMail::Sender::Simple.new(attributes)
|
32
38
|
when :mock
|
33
39
|
# for testing
|
34
40
|
MultiMail::Sender::Mock.new(attributes)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module MultiMail
|
2
|
+
module Receiver
|
3
|
+
class SendGrid < MultiMail::Service
|
4
|
+
include MultiMail::Receiver::Base
|
5
|
+
|
6
|
+
requires :sendgrid_username
|
7
|
+
requires :sendgrid_password
|
8
|
+
recognizes :http_post_format
|
9
|
+
attr_reader :http_post_format
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
super
|
13
|
+
@sendgrid_username = options[:sendgrid_username]
|
14
|
+
@sendgrid_password = options[:sendgrid_password]
|
15
|
+
@http_post_format = options[:http_post_format]
|
16
|
+
end
|
17
|
+
|
18
|
+
def transform(params)
|
19
|
+
attachments = 1.upto(params['attachments'].to_i).map do |num|
|
20
|
+
attachment_from_params(params["attachment#{num}"])
|
21
|
+
end
|
22
|
+
|
23
|
+
@message = Mail.new do
|
24
|
+
header params['headers']
|
25
|
+
|
26
|
+
body params['text']
|
27
|
+
|
28
|
+
html_part do
|
29
|
+
content_type 'text/html; charset=UTF-8'
|
30
|
+
body params['html']
|
31
|
+
end if params['html']
|
32
|
+
|
33
|
+
attachments.each do |attachment|
|
34
|
+
add_file(attachment)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
data/lib/multi_mail/service.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module MultiMail
|
2
|
+
# Interacts with email APIs to send or receive email.
|
3
|
+
#
|
2
4
|
# @see http://rdoc.info/gems/fog/Fog/Service
|
3
5
|
class Service
|
6
|
+
# Initializers an email API service.
|
7
|
+
#
|
4
8
|
# @param [Hash] options optional arguments
|
5
9
|
def initialize(options = {})
|
6
10
|
self.class.validate_options(options)
|
@@ -15,6 +19,8 @@ module MultiMail
|
|
15
19
|
requirements.concat(args)
|
16
20
|
end
|
17
21
|
|
22
|
+
# Returns the list of required arguments.
|
23
|
+
#
|
18
24
|
# @return [Array] a list of required arguments
|
19
25
|
# @see Fog::Service::requirements
|
20
26
|
def requirements
|
@@ -29,15 +35,20 @@ module MultiMail
|
|
29
35
|
recognized.concat(args)
|
30
36
|
end
|
31
37
|
|
38
|
+
# Returns the list of optional arguments.
|
39
|
+
#
|
32
40
|
# @return [Array] a list of optional arguments
|
33
41
|
# @see Fog::Service::recognized
|
34
42
|
def recognized
|
35
43
|
@recognized ||= []
|
36
44
|
end
|
37
45
|
|
46
|
+
# Ensures that required arguments are present and that optional arguments
|
47
|
+
# are recognized.
|
48
|
+
#
|
38
49
|
# @param [Hash] options arguments
|
39
|
-
# @
|
40
|
-
# recognize optional
|
50
|
+
# @raise [ArgumentError] if it can't find a required argument or can't
|
51
|
+
# recognize an optional argument
|
41
52
|
# @see Fog::Service::validate_options
|
42
53
|
def validate_options(options)
|
43
54
|
keys = []
|
@@ -48,13 +59,13 @@ module MultiMail
|
|
48
59
|
end
|
49
60
|
missing = requirements - keys
|
50
61
|
unless missing.empty?
|
51
|
-
raise ArgumentError, "Missing required arguments: #{missing.join(', ')}"
|
62
|
+
raise ArgumentError, "Missing required arguments: #{missing.map(&:to_s).sort.join(', ')}"
|
52
63
|
end
|
53
64
|
|
54
65
|
unless recognizes.empty?
|
55
66
|
unrecognized = options.keys - requirements - recognized
|
56
67
|
unless unrecognized.empty?
|
57
|
-
raise ArgumentError, "Unrecognized arguments: #{unrecognized.join(', ')}"
|
68
|
+
raise ArgumentError, "Unrecognized arguments: #{unrecognized.map(&:to_s).sort.join(', ')}"
|
58
69
|
end
|
59
70
|
end
|
60
71
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module MultiMail
|
2
|
+
module Receiver
|
3
|
+
class Simple < MultiMail::Service
|
4
|
+
include MultiMail::Receiver::Base
|
5
|
+
# Expects the value of the "message" query string parameter to be a raw
|
6
|
+
# email message parsable by the Mail gem.
|
7
|
+
#
|
8
|
+
# @param [Hash] params the content of the webhook
|
9
|
+
# @return [Array<Mail::Message>] messages
|
10
|
+
def transform(params)
|
11
|
+
[Mail.new(params['message'])]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/multi_mail/version.rb
CHANGED