mailgun-ruby 1.1.0 → 1.2.5
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 +5 -5
- data/.gitignore +1 -0
- data/.ruby-env.yml.example +1 -1
- data/.travis.yml +23 -7
- data/Gemfile +2 -0
- data/README.md +79 -18
- data/{Domains.md → docs/Domains.md} +18 -0
- data/{Events.md → docs/Events.md} +0 -0
- data/{MessageBuilder.md → docs/MessageBuilder.md} +32 -13
- 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} +1 -1
- data/docs/railgun/Overview.md +11 -0
- data/docs/railgun/Parameters.md +83 -0
- data/lib/mailgun/address.rb +48 -0
- data/lib/mailgun/client.rb +85 -8
- data/lib/mailgun/events/events.rb +40 -12
- data/lib/mailgun/exceptions/exceptions.rb +21 -7
- data/lib/mailgun/lists/opt_in_handler.rb +0 -1
- data/lib/mailgun/messages/batch_message.rb +3 -2
- data/lib/mailgun/messages/message_builder.rb +139 -30
- data/lib/mailgun/response.rb +7 -0
- data/lib/mailgun/suppressions.rb +273 -0
- data/lib/mailgun/version.rb +1 -1
- data/lib/mailgun/webhooks/webhooks.rb +1 -1
- data/lib/mailgun-ruby.rb +2 -0
- data/lib/mailgun.rb +1 -0
- data/lib/railgun/attachment.rb +56 -0
- data/lib/railgun/errors.rb +27 -0
- data/lib/railgun/mailer.rb +253 -0
- data/lib/railgun/message.rb +18 -0
- data/lib/railgun/railtie.rb +10 -0
- data/lib/railgun.rb +8 -0
- data/mailgun.gemspec +12 -13
- data/spec/integration/email_validation_spec.rb +57 -15
- data/spec/integration/events_spec.rb +9 -1
- data/spec/integration/mailer_spec.rb +67 -0
- data/spec/integration/mailgun_spec.rb +51 -1
- data/spec/integration/suppressions_spec.rb +142 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/unit/connection/test_client.rb +16 -0
- data/spec/unit/events/events_spec.rb +36 -2
- data/spec/unit/mailgun_spec.rb +32 -10
- data/spec/unit/messages/batch_message_spec.rb +56 -40
- data/spec/unit/messages/message_builder_spec.rb +267 -81
- data/spec/unit/messages/sample_data/unknown.type +0 -0
- data/spec/unit/railgun/content_type_spec.rb +71 -0
- data/spec/unit/railgun/mailer_spec.rb +388 -0
- data/vcr_cassettes/email_validation.yml +136 -25
- data/vcr_cassettes/events.yml +48 -1
- data/vcr_cassettes/exceptions.yml +45 -0
- data/vcr_cassettes/mailer_invalid_domain.yml +109 -0
- data/vcr_cassettes/message_deliver.yml +149 -0
- data/vcr_cassettes/suppressions.yml +727 -0
- metadata +65 -40
data/lib/mailgun/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'mailgun/chains'
|
2
|
+
require 'mailgun/suppressions'
|
2
3
|
require 'mailgun/exceptions/exceptions'
|
3
4
|
|
4
5
|
module Mailgun
|
@@ -12,13 +13,50 @@ module Mailgun
|
|
12
13
|
def initialize(api_key = Mailgun.api_key,
|
13
14
|
api_host = 'api.mailgun.net',
|
14
15
|
api_version = 'v3',
|
15
|
-
ssl = true
|
16
|
+
ssl = true,
|
17
|
+
test_mode = false,
|
18
|
+
timeout = nil,
|
19
|
+
proxy_url = nil)
|
20
|
+
|
21
|
+
rest_client_params = {
|
22
|
+
user: 'api',
|
23
|
+
password: api_key,
|
24
|
+
user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}"
|
25
|
+
}
|
26
|
+
rest_client_params[:timeout] = timeout if timeout
|
16
27
|
|
17
28
|
endpoint = endpoint_generator(api_host, api_version, ssl)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
29
|
+
RestClient.proxy = proxy_url
|
30
|
+
@http_client = RestClient::Resource.new(endpoint, rest_client_params)
|
31
|
+
@test_mode = test_mode
|
32
|
+
end
|
33
|
+
|
34
|
+
# Enable test mode
|
35
|
+
#
|
36
|
+
# Prevents sending of any messages.
|
37
|
+
def enable_test_mode!
|
38
|
+
@test_mode = true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Disable test mode
|
42
|
+
#
|
43
|
+
# Reverts the test_mode flag and allows the client to send messages.
|
44
|
+
def disable_test_mode!
|
45
|
+
@test_mode = false
|
46
|
+
end
|
47
|
+
|
48
|
+
# Client is in test mode?
|
49
|
+
#
|
50
|
+
# @return [Boolean] Is the client set in test mode?
|
51
|
+
def test_mode?
|
52
|
+
@test_mode
|
53
|
+
end
|
54
|
+
|
55
|
+
# Provides a store of all the emails sent in test mode so you can check them.
|
56
|
+
#
|
57
|
+
# @return [Hash]
|
58
|
+
def self.deliveries
|
59
|
+
@@deliveries ||= []
|
22
60
|
end
|
23
61
|
|
24
62
|
# Simple Message Sending
|
@@ -28,8 +66,25 @@ module Mailgun
|
|
28
66
|
# containing required parameters for the requested resource.
|
29
67
|
# @return [Mailgun::Response] A Mailgun::Response object.
|
30
68
|
def send_message(working_domain, data)
|
69
|
+
perform_data_validation(working_domain, data)
|
70
|
+
|
71
|
+
if test_mode? then
|
72
|
+
Mailgun::Client.deliveries << data
|
73
|
+
return Response.from_hash(
|
74
|
+
{
|
75
|
+
:body => "{\"id\": \"test-mode-mail-#{SecureRandom.uuid}@localhost\", \"message\": \"Queued. Thank you.\"}",
|
76
|
+
:code => 200,
|
77
|
+
}
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
31
81
|
case data
|
32
82
|
when Hash
|
83
|
+
# Remove nil values from the data hash
|
84
|
+
# Submitting nils to the API will likely cause an error.
|
85
|
+
# See also: https://github.com/mailgun/mailgun-ruby/issues/32
|
86
|
+
data = data.select { |k, v| v != nil }
|
87
|
+
|
33
88
|
if data.key?(:message)
|
34
89
|
if data[:message].is_a?(String)
|
35
90
|
data[:message] = convert_string_to_file(data[:message])
|
@@ -50,9 +105,10 @@ module Mailgun
|
|
50
105
|
# with. Be sure to include your domain, where necessary.
|
51
106
|
# @param [Hash] data This should be a standard Hash
|
52
107
|
# containing required parameters for the requested resource.
|
108
|
+
# @param [Hash] headers Additional headers to pass to the resource.
|
53
109
|
# @return [Mailgun::Response] A Mailgun::Response object.
|
54
|
-
def post(resource_path, data)
|
55
|
-
response = @http_client[resource_path].post(data)
|
110
|
+
def post(resource_path, data, headers = {})
|
111
|
+
response = @http_client[resource_path].post(data, headers)
|
56
112
|
Response.new(response)
|
57
113
|
rescue => err
|
58
114
|
raise communication_error err
|
@@ -62,8 +118,9 @@ module Mailgun
|
|
62
118
|
#
|
63
119
|
# @param [String] resource_path This is the API resource you wish to interact
|
64
120
|
# with. Be sure to include your domain, where necessary.
|
65
|
-
# @param [Hash]
|
121
|
+
# @param [Hash] params This should be a standard Hash
|
66
122
|
# containing required parameters for the requested resource.
|
123
|
+
# @param [String] accept Acceptable Content-Type of the response body.
|
67
124
|
# @return [Mailgun::Response] A Mailgun::Response object.
|
68
125
|
def get(resource_path, params = nil, accept = '*/*')
|
69
126
|
if params
|
@@ -102,6 +159,14 @@ module Mailgun
|
|
102
159
|
raise communication_error err
|
103
160
|
end
|
104
161
|
|
162
|
+
# Constructs a Suppressions client for the given domain.
|
163
|
+
#
|
164
|
+
# @param [String] domain Domain which suppressions requests will be made for
|
165
|
+
# @return [Mailgun::Suppressions]
|
166
|
+
def suppressions(domain)
|
167
|
+
Suppressions.new(self, domain)
|
168
|
+
end
|
169
|
+
|
105
170
|
private
|
106
171
|
|
107
172
|
# Converts MIME string to file for easy uploading to API
|
@@ -139,5 +204,17 @@ module Mailgun
|
|
139
204
|
CommunicationError.new(e.message)
|
140
205
|
end
|
141
206
|
|
207
|
+
def perform_data_validation(working_domain, data)
|
208
|
+
message = data.respond_to?(:message) ? data.message : data
|
209
|
+
fail ParameterError.new('Missing working domain', working_domain) unless working_domain
|
210
|
+
fail ParameterError.new(
|
211
|
+
'Missing `to` recipient, message should containg at least 1 recipient',
|
212
|
+
working_domain
|
213
|
+
) if message.fetch('to', []).empty? && message.fetch(:to, []).empty?
|
214
|
+
fail ParameterError.new(
|
215
|
+
'Missing a `from` sender, message should containg at least 1 `from` sender',
|
216
|
+
working_domain
|
217
|
+
) if message.fetch('from', []).empty? && message.fetch(:from, []).empty?
|
218
|
+
end
|
142
219
|
end
|
143
220
|
end
|
@@ -11,6 +11,7 @@ module Mailgun
|
|
11
11
|
#
|
12
12
|
# See the Github documentation for full examples.
|
13
13
|
class Events
|
14
|
+
include Enumerable
|
14
15
|
|
15
16
|
# Public: event initializer
|
16
17
|
#
|
@@ -23,31 +24,47 @@ module Mailgun
|
|
23
24
|
@paging_previous = nil
|
24
25
|
end
|
25
26
|
|
26
|
-
# Public: Issues a simple get against the client.
|
27
|
+
# Public: Issues a simple get against the client. Alias of `next`.
|
27
28
|
#
|
28
29
|
# params - a Hash of query options and/or filters.
|
29
30
|
#
|
30
31
|
# Returns a Mailgun::Response object.
|
31
32
|
def get(params = nil)
|
32
|
-
|
33
|
+
self.next(params)
|
33
34
|
end
|
34
35
|
|
35
36
|
# Public: Using built in paging, obtains the next set of data.
|
36
37
|
# If an events request hasn't been sent previously, this will send one
|
37
38
|
# without parameters
|
38
39
|
#
|
40
|
+
# params - a Hash of query options and/or filters.
|
41
|
+
#
|
39
42
|
# Returns a Mailgun::Response object.
|
40
|
-
def next
|
41
|
-
get_events(
|
43
|
+
def next(params = nil)
|
44
|
+
get_events(params, @paging_next)
|
42
45
|
end
|
43
46
|
|
44
47
|
# Public: Using built in paging, obtains the previous set of data.
|
45
48
|
# If an events request hasn't been sent previously, this will send one
|
46
49
|
# without parameters
|
47
50
|
#
|
51
|
+
# params - a Hash of query options and/or filters.
|
52
|
+
#
|
48
53
|
# Returns Mailgun::Response object.
|
49
|
-
def previous
|
50
|
-
get_events(
|
54
|
+
def previous(params = nil)
|
55
|
+
get_events(params, @paging_previous)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Public: Allows iterating through all events and performs automatic paging.
|
59
|
+
#
|
60
|
+
# &block - Block to execute on items.
|
61
|
+
def each(&block)
|
62
|
+
items = self.next.to_h['items']
|
63
|
+
|
64
|
+
until items.empty?
|
65
|
+
items.each(&block)
|
66
|
+
items = self.next.to_h['items']
|
67
|
+
end
|
51
68
|
end
|
52
69
|
|
53
70
|
private
|
@@ -70,12 +87,23 @@ module Mailgun
|
|
70
87
|
#
|
71
88
|
# Return is irrelevant.
|
72
89
|
def extract_paging(response)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
@
|
78
|
-
|
90
|
+
paging = response.to_h['paging']
|
91
|
+
next_page_url = paging && paging['next'] # gives nil when any one of the keys doens't exist
|
92
|
+
previous_page_url = paging && paging['previous'] # can be replaced with Hash#dig for ruby >= 2.3.0
|
93
|
+
@paging_next = extract_endpoint_from(next_page_url)
|
94
|
+
@paging_previous = extract_endpoint_from(previous_page_url)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Internal: given a paging URL, extract the endpoint
|
98
|
+
#
|
99
|
+
# response - the endpoint for the previous/next page
|
100
|
+
#
|
101
|
+
# Returns a String of the partial URI if the given url follows the regular API format
|
102
|
+
# Returns nil in other cases (e.g. when given nil, or an irrelevant url)
|
103
|
+
def extract_endpoint_from(url = nil)
|
104
|
+
URI.parse(url).path[/\/v[\d]\/#{@domain}\/events\/(.+)/,1]
|
105
|
+
rescue URI::InvalidURIError
|
106
|
+
nil
|
79
107
|
end
|
80
108
|
|
81
109
|
# Internal: construct the event path to be used by the client
|
@@ -34,19 +34,33 @@ module Mailgun
|
|
34
34
|
|
35
35
|
# Public: fallback if there is no response code on the object
|
36
36
|
NOCODE = 000
|
37
|
+
FORBIDDEN = 'Forbidden'
|
37
38
|
|
38
39
|
# Public: initialization of new error given a message and/or object
|
39
40
|
#
|
40
|
-
# message
|
41
|
-
#
|
41
|
+
# message - a String detailing the error
|
42
|
+
# response - a RestClient::Response object
|
42
43
|
#
|
43
|
-
def initialize(message = nil,
|
44
|
-
@
|
45
|
-
@code =
|
46
|
-
|
44
|
+
def initialize(message = nil, response = nil)
|
45
|
+
@response = response
|
46
|
+
@code = response.code || NOCODE
|
47
|
+
|
48
|
+
begin
|
49
|
+
api_message = JSON.parse(response.body)['message']
|
50
|
+
rescue JSON::ParserError
|
51
|
+
api_message = response.body
|
52
|
+
rescue NoMethodError
|
53
|
+
api_message = "Unknown API error"
|
54
|
+
end
|
55
|
+
api_message = api_message + ' - Invalid Domain or API key' if api_message == FORBIDDEN
|
56
|
+
|
57
|
+
message = message || ''
|
58
|
+
message = message + ': ' + api_message
|
59
|
+
|
60
|
+
super(message, response)
|
47
61
|
rescue NoMethodError, JSON::ParserError
|
48
62
|
@code = NOCODE
|
49
|
-
super(message)
|
63
|
+
super(message, response)
|
50
64
|
end
|
51
65
|
|
52
66
|
end
|
@@ -48,7 +48,7 @@ module Mailgun
|
|
48
48
|
send_message if @counters[:recipients][recipient_type] == Mailgun::Chains::MAX_RECIPIENTS
|
49
49
|
|
50
50
|
compiled_address = parse_address(address, variables)
|
51
|
-
|
51
|
+
set_multi_complex(recipient_type, compiled_address)
|
52
52
|
|
53
53
|
store_recipient_variables(recipient_type, address, variables) if recipient_type != :from
|
54
54
|
|
@@ -84,7 +84,7 @@ module Mailgun
|
|
84
84
|
# @return [Boolean]
|
85
85
|
def send_message
|
86
86
|
rkey = 'recipient-variables'
|
87
|
-
|
87
|
+
set_multi_simple rkey, JSON.generate(@recipient_variables)
|
88
88
|
@message[rkey] = @message[rkey].first if @message.key?(rkey)
|
89
89
|
|
90
90
|
response = @client.send_message(@domain, @message).to_h!
|
@@ -111,6 +111,7 @@ module Mailgun
|
|
111
111
|
# This method resets the message object to prepare for the next batch
|
112
112
|
# of recipients.
|
113
113
|
def reset_message
|
114
|
+
@recipient_variables = {}
|
114
115
|
@message.delete('recipient-variables')
|
115
116
|
@message.delete(:to)
|
116
117
|
@message.delete(:cc)
|
@@ -1,5 +1,5 @@
|
|
1
|
+
require 'mime/types'
|
1
2
|
require 'time'
|
2
|
-
require 'json'
|
3
3
|
|
4
4
|
module Mailgun
|
5
5
|
|
@@ -24,17 +24,24 @@ module Mailgun
|
|
24
24
|
|
25
25
|
# Adds a specific type of recipient to the message object.
|
26
26
|
#
|
27
|
+
# WARNING: Setting 'h:reply-to' with add_recipient() is deprecated! Use 'reply_to' instead.
|
28
|
+
#
|
27
29
|
# @param [String] recipient_type The type of recipient. "to", "cc", "bcc" or "h:reply-to".
|
28
30
|
# @param [String] address The email address of the recipient to add to the message object.
|
29
31
|
# @param [Hash] variables A hash of the variables associated with the recipient. We recommend "first" and "last" at a minimum!
|
30
32
|
# @return [void]
|
31
33
|
def add_recipient(recipient_type, address, variables = nil)
|
34
|
+
if recipient_type == "h:reply-to"
|
35
|
+
warn 'DEPRECATION: "add_recipient("h:reply-to", ...)" is deprecated. Please use "reply_to" instead.'
|
36
|
+
return reply_to(address, variables)
|
37
|
+
end
|
38
|
+
|
32
39
|
if (@counters[:recipients][recipient_type] || 0) >= Mailgun::Chains::MAX_RECIPIENTS
|
33
40
|
fail Mailgun::ParameterError, 'Too many recipients added to message.', address
|
34
41
|
end
|
35
42
|
|
36
43
|
compiled_address = parse_address(address, variables)
|
37
|
-
|
44
|
+
set_multi_complex(recipient_type, compiled_address)
|
38
45
|
|
39
46
|
@counters[:recipients][recipient_type] += 1 if @counters[:recipients].key?(recipient_type)
|
40
47
|
end
|
@@ -54,12 +61,25 @@ module Mailgun
|
|
54
61
|
from(address, variables)
|
55
62
|
end
|
56
63
|
|
64
|
+
# Set the message's Reply-To address.
|
65
|
+
#
|
66
|
+
# Rationale: According to RFC, only one Reply-To address is allowed, so it
|
67
|
+
# is *okay* to bypass the set_multi_simple and set reply-to directly.
|
68
|
+
#
|
69
|
+
# @param [String] address The email address to provide as Reply-To.
|
70
|
+
# @param [Hash] variables A hash of variables associated with the recipient.
|
71
|
+
# @return [void]
|
72
|
+
def reply_to(address, variables = nil)
|
73
|
+
compiled_address = parse_address(address, variables)
|
74
|
+
header("reply-to", compiled_address)
|
75
|
+
end
|
76
|
+
|
57
77
|
# Set a subject for the message object
|
58
78
|
#
|
59
79
|
# @param [String] subject The subject for the email.
|
60
80
|
# @return [void]
|
61
81
|
def subject(subj = nil)
|
62
|
-
|
82
|
+
set_multi_simple(:subject, subj)
|
63
83
|
end
|
64
84
|
|
65
85
|
# Deprecated: Please use "subject" instead.
|
@@ -73,7 +93,7 @@ module Mailgun
|
|
73
93
|
# @param [String] text_body The text body for the email.
|
74
94
|
# @return [void]
|
75
95
|
def body_text(text_body = nil)
|
76
|
-
|
96
|
+
set_multi_simple(:text, text_body)
|
77
97
|
end
|
78
98
|
|
79
99
|
# Deprecated: Please use "body_text" instead.
|
@@ -87,7 +107,7 @@ module Mailgun
|
|
87
107
|
# @param [String] html_body The html body for the email.
|
88
108
|
# @return [void]
|
89
109
|
def body_html(html_body = nil)
|
90
|
-
|
110
|
+
set_multi_simple(:html, html_body)
|
91
111
|
end
|
92
112
|
|
93
113
|
# Deprecated: Please use "body_html" instead.
|
@@ -98,7 +118,7 @@ module Mailgun
|
|
98
118
|
|
99
119
|
# Adds a series of attachments, when called upon.
|
100
120
|
#
|
101
|
-
# @param [String] attachment A file object for attaching as an attachment.
|
121
|
+
# @param [String|File] attachment A file object for attaching as an attachment.
|
102
122
|
# @param [String] filename The filename you wish the attachment to be.
|
103
123
|
# @return [void]
|
104
124
|
def add_attachment(attachment, filename = nil)
|
@@ -107,19 +127,27 @@ module Mailgun
|
|
107
127
|
|
108
128
|
# Adds an inline image to the mesage object.
|
109
129
|
#
|
110
|
-
# @param [String] inline_image A file object for attaching an inline image.
|
130
|
+
# @param [String|File] inline_image A file object for attaching an inline image.
|
111
131
|
# @param [String] filename The filename you wish the inline image to be.
|
112
132
|
# @return [void]
|
113
133
|
def add_inline_image(inline_image, filename = nil)
|
114
134
|
add_file(:inline, inline_image, filename)
|
115
135
|
end
|
116
136
|
|
137
|
+
# Adds a List-Unsubscribe for the message header.
|
138
|
+
#
|
139
|
+
# @param [Array<String>] *variables Any number of url or mailto
|
140
|
+
# @return [void]
|
141
|
+
def list_unsubscribe(*variables)
|
142
|
+
set_single('h:List-Unsubscribe', variables.map { |var| "<#{var}>" }.join(','))
|
143
|
+
end
|
144
|
+
|
117
145
|
# Send a message in test mode. (The message won't really be sent to the recipient)
|
118
146
|
#
|
119
147
|
# @param [Boolean] mode The boolean or string value (will fix itself)
|
120
148
|
# @return [void]
|
121
149
|
def test_mode(mode)
|
122
|
-
|
150
|
+
set_multi_simple('o:testmode', bool_lookup(mode))
|
123
151
|
end
|
124
152
|
|
125
153
|
# Deprecated: 'set_test_mode' is depreciated. Please use 'test_mode' instead.
|
@@ -133,7 +161,7 @@ module Mailgun
|
|
133
161
|
# @param [Boolean] mode The boolean or string value(will fix itself)
|
134
162
|
# @return [void]
|
135
163
|
def dkim(mode)
|
136
|
-
|
164
|
+
set_multi_simple('o:dkim', bool_lookup(mode))
|
137
165
|
end
|
138
166
|
|
139
167
|
# Deprecated: 'set_dkim' is deprecated. Please use 'dkim' instead.
|
@@ -149,7 +177,7 @@ module Mailgun
|
|
149
177
|
def add_campaign_id(campaign_id)
|
150
178
|
fail(Mailgun::ParameterError, 'Too many campaigns added to message.', campaign_id) if @counters[:attributes][:campaign_id] >= Mailgun::Chains::MAX_CAMPAIGN_IDS
|
151
179
|
|
152
|
-
|
180
|
+
set_multi_complex('o:campaign', campaign_id)
|
153
181
|
@counters[:attributes][:campaign_id] += 1
|
154
182
|
end
|
155
183
|
|
@@ -161,7 +189,7 @@ module Mailgun
|
|
161
189
|
if @counters[:attributes][:tag] >= Mailgun::Chains::MAX_TAGS
|
162
190
|
fail Mailgun::ParameterError, 'Too many tags added to message.', tag
|
163
191
|
end
|
164
|
-
|
192
|
+
set_multi_complex('o:tag', tag)
|
165
193
|
@counters[:attributes][:tag] += 1
|
166
194
|
end
|
167
195
|
|
@@ -170,7 +198,9 @@ module Mailgun
|
|
170
198
|
# @param [Boolean] tracking Boolean true or false.
|
171
199
|
# @return [void]
|
172
200
|
def track_opens(mode)
|
173
|
-
|
201
|
+
value = bool_lookup(mode)
|
202
|
+
set_single('o:tracking-opens', value)
|
203
|
+
set_multi_simple('o:tracking', value)
|
174
204
|
end
|
175
205
|
|
176
206
|
# Deprecated: 'set_open_tracking' is deprecated. Please use 'track_opens' instead.
|
@@ -184,7 +214,9 @@ module Mailgun
|
|
184
214
|
# @param [String] mode True, False, or HTML (for HTML only tracking)
|
185
215
|
# @return [void]
|
186
216
|
def track_clicks(mode)
|
187
|
-
|
217
|
+
value = bool_lookup(mode)
|
218
|
+
set_single('o:tracking-clicks', value)
|
219
|
+
set_multi_simple('o:tracking', value)
|
188
220
|
end
|
189
221
|
|
190
222
|
# Depreciated: 'set_click_tracking. is deprecated. Please use 'track_clicks' instead.
|
@@ -202,7 +234,7 @@ module Mailgun
|
|
202
234
|
# @return [void]
|
203
235
|
def deliver_at(timestamp)
|
204
236
|
time_str = DateTime.parse(timestamp)
|
205
|
-
|
237
|
+
set_multi_simple('o:deliverytime', time_str.rfc2822)
|
206
238
|
end
|
207
239
|
|
208
240
|
# Deprecated: 'set_delivery_time' is deprecated. Please use 'deliver_at' instead.
|
@@ -219,8 +251,12 @@ module Mailgun
|
|
219
251
|
# @return [void]
|
220
252
|
def header(name, data)
|
221
253
|
fail(Mailgun::ParameterError, 'Header name for message must be specified') if name.to_s.empty?
|
222
|
-
|
223
|
-
|
254
|
+
begin
|
255
|
+
jsondata = make_json data
|
256
|
+
set_single("h:#{name}", jsondata)
|
257
|
+
rescue Mailgun::ParameterError
|
258
|
+
set_single("h:#{name}", data)
|
259
|
+
end
|
224
260
|
end
|
225
261
|
|
226
262
|
# Deprecated: 'set_custom_data' is deprecated. Please use 'header' instead.
|
@@ -229,6 +265,23 @@ module Mailgun
|
|
229
265
|
header name, data
|
230
266
|
end
|
231
267
|
|
268
|
+
# Attaches custom JSON data to the message. See the following doc page for more info.
|
269
|
+
# https://documentation.mailgun.com/user_manual.html#attaching-data-to-messages
|
270
|
+
#
|
271
|
+
# @param [String] name A name for the custom variable block.
|
272
|
+
# @param [String|Hash] data Either a string or a hash. If it is not valid JSON or
|
273
|
+
# can not be converted to JSON, ParameterError will be raised.
|
274
|
+
# @return [void]
|
275
|
+
def variable(name, data)
|
276
|
+
fail(Mailgun::ParameterError, 'Variable name must be specified') if name.to_s.empty?
|
277
|
+
begin
|
278
|
+
jsondata = make_json data
|
279
|
+
set_single("v:#{name}", jsondata)
|
280
|
+
rescue Mailgun::ParameterError
|
281
|
+
set_single("v:#{name}", data)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
232
285
|
# Add custom parameter to the message. A custom parameter is any parameter that
|
233
286
|
# is not yet supported by the SDK, but available at the API. Note: No validation
|
234
287
|
# is performed. Don't forget to prefix the parameter with o, h, or v.
|
@@ -237,7 +290,7 @@ module Mailgun
|
|
237
290
|
# @param [string] data A string of data for the parameter.
|
238
291
|
# @return [void]
|
239
292
|
def add_custom_parameter(name, data)
|
240
|
-
|
293
|
+
set_multi_complex(name, data)
|
241
294
|
end
|
242
295
|
|
243
296
|
# Set the Message-Id header to a custom value. Don't forget to enclose the
|
@@ -250,7 +303,7 @@ module Mailgun
|
|
250
303
|
def message_id(data = nil)
|
251
304
|
key = 'h:Message-Id'
|
252
305
|
return @message.delete(key) if data.to_s.empty?
|
253
|
-
|
306
|
+
set_single(key, data)
|
254
307
|
end
|
255
308
|
|
256
309
|
# Deprecated: 'set_message_id' is deprecated. Use 'message_id' instead.
|
@@ -259,15 +312,57 @@ module Mailgun
|
|
259
312
|
message_id data
|
260
313
|
end
|
261
314
|
|
315
|
+
# Set name of a template stored via template API. See Templates for more information
|
316
|
+
# https://documentation.mailgun.com/en/latest/api-templates.html
|
317
|
+
#
|
318
|
+
# @param [String] tag A defined template name to use. Passing nil or
|
319
|
+
# empty string will delete template key and value from @message hash.
|
320
|
+
# @return [void]
|
321
|
+
def template(template_name = nil)
|
322
|
+
key = 'template'
|
323
|
+
return @message.delete(key) if template_name.to_s.empty?
|
324
|
+
set_single(key, template_name)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Set specific template version.
|
328
|
+
#
|
329
|
+
# @param [String] tag A defined template name to use. Passing nil or
|
330
|
+
# empty string will delete template key and value from @message hash.
|
331
|
+
# @return [void]
|
332
|
+
def template_version(version = nil)
|
333
|
+
key = 't:version'
|
334
|
+
return @message.delete(key) if version.to_s.empty?
|
335
|
+
set_single(key, version)
|
336
|
+
end
|
337
|
+
|
338
|
+
# Turn off or on template rendering in the text part
|
339
|
+
# of the message in case of template sending.
|
340
|
+
#
|
341
|
+
# @param [Boolean] tracking Boolean true or false.
|
342
|
+
# @return [void]
|
343
|
+
def template_text(mode)
|
344
|
+
set_single('t:text', bool_lookup(mode))
|
345
|
+
end
|
346
|
+
|
262
347
|
private
|
263
348
|
|
349
|
+
# Sets a single value in the message hash where "multidict" features are not needed.
|
350
|
+
# Does *not* permit duplicate params.
|
351
|
+
#
|
352
|
+
# @param [String] parameter The message object parameter name.
|
353
|
+
# @param [String] value The value of the parameter.
|
354
|
+
# @return [void]
|
355
|
+
def set_single(parameter, value)
|
356
|
+
@message[parameter] = value ? value : ''
|
357
|
+
end
|
358
|
+
|
264
359
|
# Sets values within the multidict, however, prevents
|
265
360
|
# duplicate values for keys.
|
266
361
|
#
|
267
362
|
# @param [String] parameter The message object parameter name.
|
268
363
|
# @param [String] value The value of the parameter.
|
269
364
|
# @return [void]
|
270
|
-
def
|
365
|
+
def set_multi_simple(parameter, value)
|
271
366
|
@message[parameter] = value ? [value] : ['']
|
272
367
|
end
|
273
368
|
|
@@ -277,7 +372,7 @@ module Mailgun
|
|
277
372
|
# @param [String] parameter The message object parameter name.
|
278
373
|
# @param [String] value The value of the parameter.
|
279
374
|
# @return [void]
|
280
|
-
def
|
375
|
+
def set_multi_complex(parameter, value)
|
281
376
|
@message[parameter] << (value || '')
|
282
377
|
end
|
283
378
|
|
@@ -288,6 +383,7 @@ module Mailgun
|
|
288
383
|
def bool_lookup(value)
|
289
384
|
return 'yes' if %w(true yes yep).include? value.to_s.downcase
|
290
385
|
return 'no' if %w(false no nope).include? value.to_s.downcase
|
386
|
+
warn 'WARN: for bool type actions next values are prefered: true yes yep | false no nope | htmlonly'
|
291
387
|
value
|
292
388
|
end
|
293
389
|
|
@@ -308,9 +404,9 @@ module Mailgun
|
|
308
404
|
#
|
309
405
|
# Returns a JSON object or raises ParameterError
|
310
406
|
def make_json(obj)
|
311
|
-
return JSON.parse(obj).
|
312
|
-
return obj.
|
313
|
-
return JSON.generate(obj).
|
407
|
+
return JSON.parse(obj).to_json if obj.is_a?(String)
|
408
|
+
return obj.to_json if obj.is_a?(Hash)
|
409
|
+
return JSON.generate(obj).to_json
|
314
410
|
rescue
|
315
411
|
raise Mailgun::ParameterError, 'Provided data could not be made into JSON. Try a JSON string or Hash.', obj
|
316
412
|
end
|
@@ -325,19 +421,26 @@ module Mailgun
|
|
325
421
|
def parse_address(address, vars)
|
326
422
|
return address unless vars.is_a? Hash
|
327
423
|
fail(Mailgun::ParameterError, 'Email address not specified') unless address.is_a? String
|
424
|
+
if vars['full_name'] != nil && (vars['first'] != nil || vars['last'] != nil)
|
425
|
+
fail(Mailgun::ParameterError, 'Must specify at most one of full_name or first/last. Vars passed: #{vars}')
|
426
|
+
end
|
328
427
|
|
329
|
-
|
428
|
+
if vars['full_name']
|
429
|
+
full_name = vars['full_name']
|
430
|
+
elsif vars['first'] || vars['last']
|
431
|
+
full_name = "#{vars['first']} #{vars['last']}".strip
|
432
|
+
end
|
330
433
|
|
331
|
-
return "'#{full_name}' <#{address}>" if
|
434
|
+
return "'#{full_name}' <#{address}>" if full_name
|
332
435
|
address
|
333
436
|
end
|
334
437
|
|
335
438
|
# Private: Adds a file to the message.
|
336
439
|
#
|
337
|
-
# disposition
|
338
|
-
#
|
339
|
-
#
|
340
|
-
#
|
440
|
+
# @param [Symbol] disposition The type of file: :attachment or :inline
|
441
|
+
# @param [String|File] attachment A file object for attaching as an attachment.
|
442
|
+
# @param [String] filename The filename you wish the attachment to be.
|
443
|
+
# @return [void]
|
341
444
|
#
|
342
445
|
# Returns nothing
|
343
446
|
def add_file(disposition, filedata, filename)
|
@@ -348,11 +451,17 @@ module Mailgun
|
|
348
451
|
'Unable to access attachment file object.'
|
349
452
|
) unless attachment.respond_to?(:read)
|
350
453
|
|
454
|
+
if attachment.respond_to?(:path) && !attachment.respond_to?(:content_type)
|
455
|
+
mime_types = MIME::Types.type_for(attachment.path)
|
456
|
+
content_type = mime_types.empty? ? 'application/octet-stream' : mime_types[0].content_type
|
457
|
+
attachment.instance_eval "def content_type; '#{content_type}'; end"
|
458
|
+
end
|
459
|
+
|
351
460
|
unless filename.nil?
|
352
461
|
attachment.instance_variable_set :@original_filename, filename
|
353
462
|
attachment.instance_eval 'def original_filename; @original_filename; end'
|
354
463
|
end
|
355
|
-
|
464
|
+
set_multi_complex(disposition, attachment)
|
356
465
|
end
|
357
466
|
end
|
358
467
|
|