mailgun-ruby 1.1.2 → 1.1.6
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.
- checksums.yaml +4 -4
- data/.ruby-env.yml.example +1 -1
- data/.travis.yml +6 -4
- data/README.md +46 -8
- data/{Domains.md → docs/Domains.md} +18 -0
- data/{Events.md → docs/Events.md} +0 -0
- data/{MessageBuilder.md → docs/MessageBuilder.md} +21 -5
- data/{Messages.md → docs/Messages.md} +3 -3
- data/{OptInHandler.md → docs/OptInHandler.md} +0 -0
- data/{Snippets.md → docs/Snippets.md} +21 -2
- data/docs/Suppressions.md +82 -0
- data/{Webhooks.md → docs/Webhooks.md} +0 -0
- data/lib/mailgun/client.rb +27 -3
- data/lib/mailgun/events/events.rb +23 -6
- data/lib/mailgun/messages/batch_message.rb +2 -2
- data/lib/mailgun/messages/message_builder.rb +79 -24
- data/lib/mailgun/suppressions.rb +270 -0
- data/lib/mailgun/version.rb +1 -1
- data/lib/mailgun-ruby.rb +2 -1
- data/lib/railgun/attachment.rb +56 -0
- data/lib/railgun/errors.rb +27 -0
- data/lib/railgun/mailer.rb +158 -0
- data/lib/railgun/message.rb +17 -0
- data/lib/railgun/railtie.rb +9 -0
- data/lib/railgun.rb +8 -0
- data/mailgun.gemspec +1 -1
- data/spec/integration/events_spec.rb +9 -1
- data/spec/integration/mailgun_spec.rb +0 -0
- data/spec/integration/suppressions_spec.rb +126 -0
- data/spec/unit/events/events_spec.rb +17 -2
- data/spec/unit/messages/message_builder_spec.rb +44 -7
- data/vcr_cassettes/events.yml +48 -1
- data/vcr_cassettes/suppressions.yml +676 -0
- metadata +21 -10
@@ -23,17 +23,24 @@ module Mailgun
|
|
23
23
|
|
24
24
|
# Adds a specific type of recipient to the message object.
|
25
25
|
#
|
26
|
+
# WARNING: Setting 'h:reply-to' with add_recipient() is deprecated! Use 'reply_to' instead.
|
27
|
+
#
|
26
28
|
# @param [String] recipient_type The type of recipient. "to", "cc", "bcc" or "h:reply-to".
|
27
29
|
# @param [String] address The email address of the recipient to add to the message object.
|
28
30
|
# @param [Hash] variables A hash of the variables associated with the recipient. We recommend "first" and "last" at a minimum!
|
29
31
|
# @return [void]
|
30
32
|
def add_recipient(recipient_type, address, variables = nil)
|
33
|
+
if recipient_type == "h:reply-to"
|
34
|
+
warn 'DEPRECATION: "add_recipient("h:reply-to", ...)" is deprecated. Please use "reply_to" instead.'
|
35
|
+
return reply_to(address, variables)
|
36
|
+
end
|
37
|
+
|
31
38
|
if (@counters[:recipients][recipient_type] || 0) >= Mailgun::Chains::MAX_RECIPIENTS
|
32
39
|
fail Mailgun::ParameterError, 'Too many recipients added to message.', address
|
33
40
|
end
|
34
41
|
|
35
42
|
compiled_address = parse_address(address, variables)
|
36
|
-
|
43
|
+
set_multi_complex(recipient_type, compiled_address)
|
37
44
|
|
38
45
|
@counters[:recipients][recipient_type] += 1 if @counters[:recipients].key?(recipient_type)
|
39
46
|
end
|
@@ -53,12 +60,25 @@ module Mailgun
|
|
53
60
|
from(address, variables)
|
54
61
|
end
|
55
62
|
|
63
|
+
# Set the message's Reply-To address.
|
64
|
+
#
|
65
|
+
# Rationale: According to RFC, only one Reply-To address is allowed, so it
|
66
|
+
# is *okay* to bypass the set_multi_simple and set reply-to directly.
|
67
|
+
#
|
68
|
+
# @param [String] address The email address to provide as Reply-To.
|
69
|
+
# @param [Hash] variables A hash of variables associated with the recipient.
|
70
|
+
# @return [void]
|
71
|
+
def reply_to(address, variables = nil)
|
72
|
+
compiled_address = parse_address(address, variables)
|
73
|
+
header("reply-to", compiled_address)
|
74
|
+
end
|
75
|
+
|
56
76
|
# Set a subject for the message object
|
57
77
|
#
|
58
78
|
# @param [String] subject The subject for the email.
|
59
79
|
# @return [void]
|
60
80
|
def subject(subj = nil)
|
61
|
-
|
81
|
+
set_multi_simple(:subject, subj)
|
62
82
|
end
|
63
83
|
|
64
84
|
# Deprecated: Please use "subject" instead.
|
@@ -72,7 +92,7 @@ module Mailgun
|
|
72
92
|
# @param [String] text_body The text body for the email.
|
73
93
|
# @return [void]
|
74
94
|
def body_text(text_body = nil)
|
75
|
-
|
95
|
+
set_multi_simple(:text, text_body)
|
76
96
|
end
|
77
97
|
|
78
98
|
# Deprecated: Please use "body_text" instead.
|
@@ -86,7 +106,7 @@ module Mailgun
|
|
86
106
|
# @param [String] html_body The html body for the email.
|
87
107
|
# @return [void]
|
88
108
|
def body_html(html_body = nil)
|
89
|
-
|
109
|
+
set_multi_simple(:html, html_body)
|
90
110
|
end
|
91
111
|
|
92
112
|
# Deprecated: Please use "body_html" instead.
|
@@ -97,7 +117,7 @@ module Mailgun
|
|
97
117
|
|
98
118
|
# Adds a series of attachments, when called upon.
|
99
119
|
#
|
100
|
-
# @param [String] attachment A file object for attaching as an attachment.
|
120
|
+
# @param [String|File] attachment A file object for attaching as an attachment.
|
101
121
|
# @param [String] filename The filename you wish the attachment to be.
|
102
122
|
# @return [void]
|
103
123
|
def add_attachment(attachment, filename = nil)
|
@@ -106,19 +126,27 @@ module Mailgun
|
|
106
126
|
|
107
127
|
# Adds an inline image to the mesage object.
|
108
128
|
#
|
109
|
-
# @param [String] inline_image A file object for attaching an inline image.
|
129
|
+
# @param [String|File] inline_image A file object for attaching an inline image.
|
110
130
|
# @param [String] filename The filename you wish the inline image to be.
|
111
131
|
# @return [void]
|
112
132
|
def add_inline_image(inline_image, filename = nil)
|
113
133
|
add_file(:inline, inline_image, filename)
|
114
134
|
end
|
115
135
|
|
136
|
+
# Adds a List-Unsubscribe for the message header.
|
137
|
+
#
|
138
|
+
# @param [Array<String>] *variables Any number of url or mailto
|
139
|
+
# @return [void]
|
140
|
+
def list_unsubscribe(*variables)
|
141
|
+
set_single('h:List-Unsubscribe', variables.map { |var| "<#{var}>" }.join(','))
|
142
|
+
end
|
143
|
+
|
116
144
|
# Send a message in test mode. (The message won't really be sent to the recipient)
|
117
145
|
#
|
118
146
|
# @param [Boolean] mode The boolean or string value (will fix itself)
|
119
147
|
# @return [void]
|
120
148
|
def test_mode(mode)
|
121
|
-
|
149
|
+
set_multi_simple('o:testmode', bool_lookup(mode))
|
122
150
|
end
|
123
151
|
|
124
152
|
# Deprecated: 'set_test_mode' is depreciated. Please use 'test_mode' instead.
|
@@ -132,7 +160,7 @@ module Mailgun
|
|
132
160
|
# @param [Boolean] mode The boolean or string value(will fix itself)
|
133
161
|
# @return [void]
|
134
162
|
def dkim(mode)
|
135
|
-
|
163
|
+
set_multi_simple('o:dkim', bool_lookup(mode))
|
136
164
|
end
|
137
165
|
|
138
166
|
# Deprecated: 'set_dkim' is deprecated. Please use 'dkim' instead.
|
@@ -148,7 +176,7 @@ module Mailgun
|
|
148
176
|
def add_campaign_id(campaign_id)
|
149
177
|
fail(Mailgun::ParameterError, 'Too many campaigns added to message.', campaign_id) if @counters[:attributes][:campaign_id] >= Mailgun::Chains::MAX_CAMPAIGN_IDS
|
150
178
|
|
151
|
-
|
179
|
+
set_multi_complex('o:campaign', campaign_id)
|
152
180
|
@counters[:attributes][:campaign_id] += 1
|
153
181
|
end
|
154
182
|
|
@@ -160,7 +188,7 @@ module Mailgun
|
|
160
188
|
if @counters[:attributes][:tag] >= Mailgun::Chains::MAX_TAGS
|
161
189
|
fail Mailgun::ParameterError, 'Too many tags added to message.', tag
|
162
190
|
end
|
163
|
-
|
191
|
+
set_multi_complex('o:tag', tag)
|
164
192
|
@counters[:attributes][:tag] += 1
|
165
193
|
end
|
166
194
|
|
@@ -169,7 +197,7 @@ module Mailgun
|
|
169
197
|
# @param [Boolean] tracking Boolean true or false.
|
170
198
|
# @return [void]
|
171
199
|
def track_opens(mode)
|
172
|
-
|
200
|
+
set_multi_simple('o:tracking-opens', bool_lookup(mode))
|
173
201
|
end
|
174
202
|
|
175
203
|
# Deprecated: 'set_open_tracking' is deprecated. Please use 'track_opens' instead.
|
@@ -183,7 +211,7 @@ module Mailgun
|
|
183
211
|
# @param [String] mode True, False, or HTML (for HTML only tracking)
|
184
212
|
# @return [void]
|
185
213
|
def track_clicks(mode)
|
186
|
-
|
214
|
+
set_multi_simple('o:tracking-clicks', bool_lookup(mode))
|
187
215
|
end
|
188
216
|
|
189
217
|
# Depreciated: 'set_click_tracking. is deprecated. Please use 'track_clicks' instead.
|
@@ -201,7 +229,7 @@ module Mailgun
|
|
201
229
|
# @return [void]
|
202
230
|
def deliver_at(timestamp)
|
203
231
|
time_str = DateTime.parse(timestamp)
|
204
|
-
|
232
|
+
set_multi_simple('o:deliverytime', time_str.rfc2822)
|
205
233
|
end
|
206
234
|
|
207
235
|
# Deprecated: 'set_delivery_time' is deprecated. Please use 'deliver_at' instead.
|
@@ -218,8 +246,12 @@ module Mailgun
|
|
218
246
|
# @return [void]
|
219
247
|
def header(name, data)
|
220
248
|
fail(Mailgun::ParameterError, 'Header name for message must be specified') if name.to_s.empty?
|
221
|
-
|
222
|
-
|
249
|
+
begin
|
250
|
+
jsondata = make_json data
|
251
|
+
set_single("h:#{name}", jsondata)
|
252
|
+
rescue Mailgun::ParameterError
|
253
|
+
set_single("h:#{name}", data)
|
254
|
+
end
|
223
255
|
end
|
224
256
|
|
225
257
|
# Deprecated: 'set_custom_data' is deprecated. Please use 'header' instead.
|
@@ -228,6 +260,19 @@ module Mailgun
|
|
228
260
|
header name, data
|
229
261
|
end
|
230
262
|
|
263
|
+
# Attaches custom JSON data to the message. See the following doc page for more info.
|
264
|
+
# https://documentation.mailgun.com/user_manual.html#attaching-data-to-messages
|
265
|
+
#
|
266
|
+
# @param [String] name A name for the custom variable block.
|
267
|
+
# @param [String|Hash] data Either a string or a hash. If it is not valid JSON or
|
268
|
+
# can not be converted to JSON, ParameterError will be raised.
|
269
|
+
# @return [void]
|
270
|
+
def variable(name, data)
|
271
|
+
fail(Mailgun::ParameterError, 'Variable name must be specified') if name.to_s.empty?
|
272
|
+
jsondata = make_json data
|
273
|
+
set_single("v:#{name}", jsondata)
|
274
|
+
end
|
275
|
+
|
231
276
|
# Add custom parameter to the message. A custom parameter is any parameter that
|
232
277
|
# is not yet supported by the SDK, but available at the API. Note: No validation
|
233
278
|
# is performed. Don't forget to prefix the parameter with o, h, or v.
|
@@ -236,7 +281,7 @@ module Mailgun
|
|
236
281
|
# @param [string] data A string of data for the parameter.
|
237
282
|
# @return [void]
|
238
283
|
def add_custom_parameter(name, data)
|
239
|
-
|
284
|
+
set_multi_complex(name, data)
|
240
285
|
end
|
241
286
|
|
242
287
|
# Set the Message-Id header to a custom value. Don't forget to enclose the
|
@@ -249,7 +294,7 @@ module Mailgun
|
|
249
294
|
def message_id(data = nil)
|
250
295
|
key = 'h:Message-Id'
|
251
296
|
return @message.delete(key) if data.to_s.empty?
|
252
|
-
|
297
|
+
set_single(key, data)
|
253
298
|
end
|
254
299
|
|
255
300
|
# Deprecated: 'set_message_id' is deprecated. Use 'message_id' instead.
|
@@ -260,13 +305,23 @@ module Mailgun
|
|
260
305
|
|
261
306
|
private
|
262
307
|
|
308
|
+
# Sets a single value in the message hash where "multidict" features are not needed.
|
309
|
+
# Does *not* permit duplicate params.
|
310
|
+
#
|
311
|
+
# @param [String] parameter The message object parameter name.
|
312
|
+
# @param [String] value The value of the parameter.
|
313
|
+
# @return [void]
|
314
|
+
def set_single(parameter, value)
|
315
|
+
@message[parameter] = value ? value : ''
|
316
|
+
end
|
317
|
+
|
263
318
|
# Sets values within the multidict, however, prevents
|
264
319
|
# duplicate values for keys.
|
265
320
|
#
|
266
321
|
# @param [String] parameter The message object parameter name.
|
267
322
|
# @param [String] value The value of the parameter.
|
268
323
|
# @return [void]
|
269
|
-
def
|
324
|
+
def set_multi_simple(parameter, value)
|
270
325
|
@message[parameter] = value ? [value] : ['']
|
271
326
|
end
|
272
327
|
|
@@ -276,7 +331,7 @@ module Mailgun
|
|
276
331
|
# @param [String] parameter The message object parameter name.
|
277
332
|
# @param [String] value The value of the parameter.
|
278
333
|
# @return [void]
|
279
|
-
def
|
334
|
+
def set_multi_complex(parameter, value)
|
280
335
|
@message[parameter] << (value || '')
|
281
336
|
end
|
282
337
|
|
@@ -307,9 +362,9 @@ module Mailgun
|
|
307
362
|
#
|
308
363
|
# Returns a JSON object or raises ParameterError
|
309
364
|
def make_json(obj)
|
310
|
-
return JSON.parse(obj).
|
311
|
-
return obj.
|
312
|
-
return JSON.generate(obj).
|
365
|
+
return JSON.parse(obj).to_json if obj.is_a?(String)
|
366
|
+
return obj.to_json if obj.is_a?(Hash)
|
367
|
+
return JSON.generate(obj).to_json
|
313
368
|
rescue
|
314
369
|
raise Mailgun::ParameterError, 'Provided data could not be made into JSON. Try a JSON string or Hash.', obj
|
315
370
|
end
|
@@ -334,7 +389,7 @@ module Mailgun
|
|
334
389
|
# Private: Adds a file to the message.
|
335
390
|
#
|
336
391
|
# @param [Symbol] disposition The type of file: :attachment or :inline
|
337
|
-
# @param [String] attachment A file object for attaching as an attachment.
|
392
|
+
# @param [String|File] attachment A file object for attaching as an attachment.
|
338
393
|
# @param [String] filename The filename you wish the attachment to be.
|
339
394
|
# @return [void]
|
340
395
|
#
|
@@ -351,7 +406,7 @@ module Mailgun
|
|
351
406
|
attachment.instance_variable_set :@original_filename, filename
|
352
407
|
attachment.instance_eval 'def original_filename; @original_filename; end'
|
353
408
|
end
|
354
|
-
|
409
|
+
set_multi_complex(disposition, attachment)
|
355
410
|
end
|
356
411
|
end
|
357
412
|
|
@@ -0,0 +1,270 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
require 'mailgun/exceptions/exceptions'
|
4
|
+
|
5
|
+
module Mailgun
|
6
|
+
|
7
|
+
# The Mailgun::Suppressions object makes it easy to manage "suppressions"
|
8
|
+
# attached to an account. "Suppressions" means bounces, unsubscribes, and complaints.
|
9
|
+
class Suppressions
|
10
|
+
|
11
|
+
# @param [Mailgun::Client] client API client to use for requests
|
12
|
+
# @param [String] domain Domain name to use for the suppression endpoints.
|
13
|
+
def initialize(client, domain)
|
14
|
+
@client = client
|
15
|
+
@domain = domain
|
16
|
+
|
17
|
+
@paging_next = nil
|
18
|
+
@paging_prev = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
####
|
22
|
+
# Paging operations
|
23
|
+
####
|
24
|
+
|
25
|
+
def next
|
26
|
+
response = get_from_paging @paging_next[:path], @paging_next[:params]
|
27
|
+
extract_paging response
|
28
|
+
response
|
29
|
+
end
|
30
|
+
|
31
|
+
def prev
|
32
|
+
response = get_from_paging @paging_prev[:path], @paging_prev[:params]
|
33
|
+
extract_paging response
|
34
|
+
response
|
35
|
+
end
|
36
|
+
|
37
|
+
####
|
38
|
+
# Bounces Endpoint (/v3/:domain/bounces)
|
39
|
+
####
|
40
|
+
|
41
|
+
def list_bounces(params = {})
|
42
|
+
response = @client.get("#{@domain}/bounces", params)
|
43
|
+
extract_paging response
|
44
|
+
response
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_bounce(address)
|
48
|
+
@client.get("#{@domain}/bounces/#{address}", nil)
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_bounce(params = {})
|
52
|
+
@client.post("#{@domain/bounces}", params)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Creates multiple bounces on the Mailgun API.
|
56
|
+
# If a bounce does not have a valid structure, it will be added to a list of unsendable bounces.
|
57
|
+
# The list of unsendable bounces will be returned at the end of this operation.
|
58
|
+
#
|
59
|
+
# If more than 999 bounce entries are provided, the list will be split and recursive calls will be made.
|
60
|
+
#
|
61
|
+
# @param [Array] data Array of bounce hashes
|
62
|
+
# @return [Response] Mailgun API response
|
63
|
+
# @return [Array] Return values from recursive call for list split.
|
64
|
+
def create_bounces(data)
|
65
|
+
# `data` should be a list of hashes, with each hash containing *at least* an `address` key.
|
66
|
+
split_return = []
|
67
|
+
if data.length >= 1000 then
|
68
|
+
resp, resp_l = create_bounces data[999..-1]
|
69
|
+
split_return.push(resp)
|
70
|
+
split_return.concat(resp_l)
|
71
|
+
data = data[0..998]
|
72
|
+
elsif data.length == 0 then
|
73
|
+
return nil, []
|
74
|
+
end
|
75
|
+
|
76
|
+
valid = []
|
77
|
+
# Validate the bounces given
|
78
|
+
# NOTE: `data` could potentially be very large (1000 elements) so it is
|
79
|
+
# more efficient to pop from data and push into a different array as
|
80
|
+
# opposed to possibly copying the entire array to another array.
|
81
|
+
while not data.empty? do
|
82
|
+
bounce = data.pop
|
83
|
+
# Bounces MUST contain a `address` key.
|
84
|
+
if not bounce.include? :address then
|
85
|
+
raise Mailgun::ParameterError.new "Bounce MUST include a :address key: #{bounce}"
|
86
|
+
end
|
87
|
+
|
88
|
+
bounce.each do |k, v|
|
89
|
+
# Hash values MUST be strings.
|
90
|
+
if not v.is_a? String then
|
91
|
+
bounce[k] = v.to_s
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
valid.push bounce
|
96
|
+
end
|
97
|
+
|
98
|
+
response = @client.post("#{@domain}/bounces", valid.to_json, { "Content-Type" => "application/json" })
|
99
|
+
return response, split_return
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete_bounce(address)
|
103
|
+
@client.delete("#{@domain}/bounces/#{address}")
|
104
|
+
end
|
105
|
+
|
106
|
+
def delete_all_bounces
|
107
|
+
@client.delete("#{@domain}/bounces")
|
108
|
+
end
|
109
|
+
|
110
|
+
####
|
111
|
+
# Unsubscribes Endpoint (/v3/:domain/unsubscribes)
|
112
|
+
####
|
113
|
+
|
114
|
+
def list_unsubscribes(params = {})
|
115
|
+
response = @client.get("#{@domain}/unsubscribes", params)
|
116
|
+
extract_paging response
|
117
|
+
response
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_unsubscribe(address)
|
121
|
+
@client.get("#{@domain}/unsubscribes/#{address}")
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_unsubscribe(params = {})
|
125
|
+
@client.post("#{@domain}/unsubscribes", params)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Creates multiple unsubscribes on the Mailgun API.
|
129
|
+
# If an unsubscribe does not have a valid structure, it will be added to a list of unsendable unsubscribes.
|
130
|
+
# The list of unsendable unsubscribes will be returned at the end of this operation.
|
131
|
+
#
|
132
|
+
# If more than 999 unsubscribe entries are provided, the list will be split and recursive calls will be made.
|
133
|
+
#
|
134
|
+
# @param [Array] data Array of unsubscribe hashes
|
135
|
+
# @return [Response] Mailgun API response
|
136
|
+
# @return [Array] Return values from recursive call for list split.
|
137
|
+
def create_unsubscribes(data)
|
138
|
+
# `data` should be a list of hashes, with each hash containing *at least* an `address` key.
|
139
|
+
split_return = []
|
140
|
+
if data.length >= 1000 then
|
141
|
+
resp, resp_l = create_unsubscribes data[999..-1]
|
142
|
+
split_return.push(resp)
|
143
|
+
split_return.concat(resp_l)
|
144
|
+
data = data[0..998]
|
145
|
+
elsif data.length == 0 then
|
146
|
+
return nil, []
|
147
|
+
end
|
148
|
+
|
149
|
+
valid = []
|
150
|
+
# Validate the unsubscribes given
|
151
|
+
while not data.empty? do
|
152
|
+
unsubscribe = data.pop
|
153
|
+
# unsubscribes MUST contain a `address` key.
|
154
|
+
if not unsubscribe.include? :address then
|
155
|
+
raise Mailgun::ParameterError.new "Unsubscribe MUST include a :address key: #{unsubscribe}"
|
156
|
+
end
|
157
|
+
|
158
|
+
unsubscribe.each do |k, v|
|
159
|
+
# Hash values MUST be strings.
|
160
|
+
if not v.is_a? String then
|
161
|
+
unsubscribe[k] = v.to_s
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
valid.push unsubscribe
|
166
|
+
end
|
167
|
+
|
168
|
+
response = @client.post("#{@domain}/unsubscribes", valid.to_json, { "Content-Type" => "application/json" })
|
169
|
+
return response, split_return
|
170
|
+
end
|
171
|
+
|
172
|
+
def delete_unsubscribe(address, params = {})
|
173
|
+
@client.delete("#{@domain}/unsubscribes/#{address}")
|
174
|
+
end
|
175
|
+
|
176
|
+
####
|
177
|
+
# Complaints Endpoint (/v3/:domain/complaints)
|
178
|
+
####
|
179
|
+
|
180
|
+
def list_complaints(params = {})
|
181
|
+
response = @client.get("#{@domain}/complaints", params)
|
182
|
+
extract_paging response
|
183
|
+
response
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_complaint(address)
|
187
|
+
@client.get("#{@domain}/complaints/#{address}", nil)
|
188
|
+
end
|
189
|
+
|
190
|
+
def create_complaint(params = {})
|
191
|
+
@client.post("#{@domain}/complaints", params)
|
192
|
+
end
|
193
|
+
|
194
|
+
# Creates multiple complaints on the Mailgun API.
|
195
|
+
# If a complaint does not have a valid structure, it will be added to a list of unsendable complaints.
|
196
|
+
# The list of unsendable complaints will be returned at the end of this operation.
|
197
|
+
#
|
198
|
+
# If more than 999 complaint entries are provided, the list will be split and recursive calls will be made.
|
199
|
+
#
|
200
|
+
# @param [Array] data Array of complaint hashes
|
201
|
+
# @return [Response] Mailgun API response
|
202
|
+
# @return [Array] Return values from recursive call for list split.
|
203
|
+
def create_complaints(data)
|
204
|
+
# `data` should be a list of hashes, with each hash containing *at least* an `address` key.
|
205
|
+
split_return = []
|
206
|
+
if data.length >= 1000 then
|
207
|
+
resp, resp_l = create_complaints data[999..-1]
|
208
|
+
split_return.push(resp)
|
209
|
+
split_return.concat(resp_l)
|
210
|
+
data = data[0..998]
|
211
|
+
elsif data.length == 0 then
|
212
|
+
return nil, []
|
213
|
+
end
|
214
|
+
|
215
|
+
valid = []
|
216
|
+
# Validate the complaints given
|
217
|
+
while not data.empty? do
|
218
|
+
complaint = data.pop
|
219
|
+
# complaints MUST contain a `address` key.
|
220
|
+
if not complaint.include? :address then
|
221
|
+
raise Mailgun::ParameterError.new "Complaint MUST include a :address key: #{complaint}"
|
222
|
+
end
|
223
|
+
|
224
|
+
complaint.each do |k, v|
|
225
|
+
# Hash values MUST be strings.
|
226
|
+
if not v.is_a? String then
|
227
|
+
complaint[k] = v.to_s
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
valid.push complaint
|
232
|
+
end
|
233
|
+
|
234
|
+
response = @client.post("#{@domain}/complaints", valid.to_json, { "Content-Type" => "application/json" })
|
235
|
+
return response, split_return
|
236
|
+
end
|
237
|
+
|
238
|
+
def delete_complaint(address)
|
239
|
+
@client.delete("#{@domain}/complaints/#{address}")
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
def get_from_paging(uri, params = {})
|
245
|
+
@client.get(uri, params)
|
246
|
+
end
|
247
|
+
|
248
|
+
def extract_paging(response)
|
249
|
+
rhash = response.to_h
|
250
|
+
return nil unless rhash.include? "paging"
|
251
|
+
|
252
|
+
page_info = rhash["paging"]
|
253
|
+
|
254
|
+
# Build the `next` endpoint
|
255
|
+
page_next = URI.parse(page_info["next"])
|
256
|
+
@paging_next = {
|
257
|
+
:path => page_next.path[/\/v[\d](.+)/, 1],
|
258
|
+
:params => Hash[URI.decode_www_form page_next.query],
|
259
|
+
}
|
260
|
+
|
261
|
+
# Build the `prev` endpoint
|
262
|
+
page_prev = URI.parse(page_info["previous"])
|
263
|
+
@paging_prev = {
|
264
|
+
:path => page_prev.path[/\/v[\d](.+)/, 1],
|
265
|
+
:params => Hash[URI.decode_www_form page_prev.query],
|
266
|
+
}
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
end
|
data/lib/mailgun/version.rb
CHANGED
data/lib/mailgun-ruby.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
require 'mailgun'
|
1
|
+
require 'mailgun'
|
2
|
+
require 'railgun' if defined?(Rails)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Railgun
|
2
|
+
|
3
|
+
class Attachment < StringIO
|
4
|
+
|
5
|
+
attr_reader :filename, :content_type, :path,
|
6
|
+
:original_filename, :overwritten_filename
|
7
|
+
|
8
|
+
def initialize(attachment, *args)
|
9
|
+
@path = ''
|
10
|
+
@inline = args.detect { |opt| opt[:inline] }
|
11
|
+
|
12
|
+
if @inline
|
13
|
+
@filename = attachment.cid
|
14
|
+
else
|
15
|
+
@filename = attachment.filename
|
16
|
+
end
|
17
|
+
|
18
|
+
@original_filename = @filename
|
19
|
+
|
20
|
+
if args.detect { |opt| opt[:filename] }
|
21
|
+
@filename = opt[:filename]
|
22
|
+
end
|
23
|
+
|
24
|
+
@overwritten_filename = @filename
|
25
|
+
|
26
|
+
@content_type = attachment.content_type.split(';')[0]
|
27
|
+
|
28
|
+
super attachment.body.decoded
|
29
|
+
end
|
30
|
+
|
31
|
+
def inline?
|
32
|
+
@inline
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_original_filename
|
36
|
+
@original_filename == @overwritten_filename
|
37
|
+
end
|
38
|
+
|
39
|
+
def source_filename
|
40
|
+
@filename
|
41
|
+
end
|
42
|
+
|
43
|
+
def attach_to_message!(mb)
|
44
|
+
if mb.nil?
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
if inline?
|
49
|
+
mb.add_inline_image self, @filename
|
50
|
+
else
|
51
|
+
mb.add_attachment self, @filename
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Railgun
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
|
5
|
+
attr_reader :object
|
6
|
+
|
7
|
+
def initialize(message = nil, object = nil)
|
8
|
+
super(message)
|
9
|
+
|
10
|
+
@object = object
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ConfigurationError < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
class InternalError < Error
|
18
|
+
|
19
|
+
attr_reader :source_exception
|
20
|
+
|
21
|
+
def initialize(source_exc, message = nil, object = nil)
|
22
|
+
super(message, object)
|
23
|
+
|
24
|
+
@source_exception = source_exc
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|