mailgun-ruby 1.1.0 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|