mailgun-ruby 1.1.8 → 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/.travis.yml +6 -5
- data/Gemfile +1 -1
- data/README.md +24 -2
- data/docs/Domains.md +0 -0
- data/docs/Webhooks.md +1 -1
- data/docs/railgun/Overview.md +11 -0
- data/docs/railgun/Parameters.md +83 -0
- data/lib/mailgun/client.rb +27 -6
- data/lib/mailgun/events/events.rb +1 -1
- data/lib/mailgun/exceptions/exceptions.rb +2 -0
- data/lib/mailgun/messages/batch_message.rb +1 -0
- data/lib/mailgun/messages/message_builder.rb +61 -6
- data/lib/mailgun/suppressions.rb +4 -1
- data/lib/mailgun/version.rb +1 -1
- data/lib/mailgun/webhooks/webhooks.rb +1 -1
- data/lib/railgun/mailer.rb +105 -13
- data/lib/railgun/message.rb +2 -1
- data/lib/railgun/railtie.rb +3 -2
- data/mailgun.gemspec +11 -11
- data/spec/integration/email_validation_spec.rb +8 -0
- data/spec/integration/events_spec.rb +1 -1
- data/spec/integration/mailer_spec.rb +67 -0
- data/spec/integration/mailgun_spec.rb +4 -1
- data/spec/integration/suppressions_spec.rb +18 -2
- data/spec/spec_helper.rb +3 -1
- data/spec/unit/connection/test_client.rb +16 -0
- data/spec/unit/events/events_spec.rb +19 -0
- data/spec/unit/mailgun_spec.rb +24 -2
- data/spec/unit/messages/batch_message_spec.rb +56 -40
- data/spec/unit/messages/message_builder_spec.rb +165 -17
- 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/mailer_invalid_domain.yml +109 -0
- data/vcr_cassettes/message_deliver.yml +149 -0
- data/vcr_cassettes/suppressions.yml +66 -15
- metadata +50 -26
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: eeb68d33e0686c3074e829fa7c33c1a9300c31bd9db3b7fde74abfdbdd681a31
|
4
|
+
data.tar.gz: dc0cd7912abb804476731ba487186a362595f7806d88f50bbbe2296da8eb0b5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9469121fbdd8341af7cc6ee395d35d8f487f556b67d8b6a0d2b6cd874f4bb1828384f9aff7c6751377fa56182b7c890947e40444f09d583d97aca8f90c41c642
|
7
|
+
data.tar.gz: 2f2b70e53e187c28ea3fcf3d3abc3f208886baca01732af0bb233c154bd171565790279620fe392259f3fa74151276d4e281389606d35ce60047b6f9a922a7cf
|
data/.travis.yml
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
language: ruby
|
2
2
|
sudo: false
|
3
3
|
rvm:
|
4
|
-
- 2.
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
- 2.
|
4
|
+
- 2.2.2
|
5
|
+
- 2.2.10
|
6
|
+
- 2.3.7
|
7
|
+
- 2.4.4
|
8
|
+
- 2.5.1
|
8
9
|
script:
|
9
10
|
- bundle install
|
10
11
|
- bundle exec rake spec
|
@@ -17,7 +18,7 @@ deploy:
|
|
17
18
|
gemspec: mailgun.gemspec
|
18
19
|
on:
|
19
20
|
tags: true
|
20
|
-
condition: "$TRAVIS_RUBY_VERSION == 2.
|
21
|
+
condition: "$TRAVIS_RUBY_VERSION == 2.5.1"
|
21
22
|
notifications:
|
22
23
|
slack:
|
23
24
|
rooms:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -19,7 +19,7 @@ gem install mailgun-ruby
|
|
19
19
|
Gemfile:
|
20
20
|
|
21
21
|
```ruby
|
22
|
-
gem 'mailgun-ruby', '~>1.
|
22
|
+
gem 'mailgun-ruby', '~>1.2.5'
|
23
23
|
```
|
24
24
|
|
25
25
|
Usage
|
@@ -27,7 +27,7 @@ Usage
|
|
27
27
|
Here's how to send a message using the library:
|
28
28
|
|
29
29
|
```ruby
|
30
|
-
require 'mailgun'
|
30
|
+
require 'mailgun-ruby'
|
31
31
|
|
32
32
|
# First, instantiate the Mailgun Client with your API key
|
33
33
|
mg_client = Mailgun::Client.new 'your-api-key'
|
@@ -56,6 +56,12 @@ domain = 'example.com'
|
|
56
56
|
result = mg_client.get("#{domain}/events", {:event => 'delivered'})
|
57
57
|
```
|
58
58
|
|
59
|
+
If you're using the EU domains, make sure you specify it when creating the client:
|
60
|
+
|
61
|
+
```
|
62
|
+
mg_client = Mailgun::Client.new 'your-api-key', 'api.eu.mailgun.net'
|
63
|
+
```
|
64
|
+
|
59
65
|
Rails
|
60
66
|
-----
|
61
67
|
|
@@ -74,9 +80,25 @@ and replace `api-myapikey` and `mydomain.com` with your secret API key and domai
|
|
74
80
|
config.action_mailer.mailgun_settings = {
|
75
81
|
api_key: 'api-myapikey',
|
76
82
|
domain: 'mydomain.com',
|
83
|
+
# api_host: 'api.eu.mailgun.net' # Uncomment this line for EU region domains
|
77
84
|
}
|
78
85
|
```
|
79
86
|
|
87
|
+
To specify Mailgun options such as campaign or tags:
|
88
|
+
```ruby
|
89
|
+
class UserMailer < ApplicationMailer
|
90
|
+
def welcome_email
|
91
|
+
mail(to: params[:to], subject: "Welcome!").tap do |message|
|
92
|
+
message.mailgun_options = {
|
93
|
+
"tag" => ["abtest-option-a", "beta-user"],
|
94
|
+
"tracking-opens" => true,
|
95
|
+
"tracking-clicks" => "htmlonly"
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
80
102
|
To get the Mailgun `message_id` after ActionMailer has successfully delivered the email:
|
81
103
|
|
82
104
|
```ruby
|
data/docs/Domains.md
CHANGED
File without changes
|
data/docs/Webhooks.md
CHANGED
@@ -31,7 +31,7 @@ hook.create 'my.perfect.domain', 'deliver', 'https://the.webhook.url/'
|
|
31
31
|
hook.remove 'my.perfect.domain', 'deliver'
|
32
32
|
|
33
33
|
# Remove all webhooks for a domain
|
34
|
-
hook.
|
34
|
+
hook.remove_all 'my.perfect.domain'
|
35
35
|
```
|
36
36
|
|
37
37
|
More Documentation
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Overview
|
2
|
+
========
|
3
|
+
|
4
|
+
Railgun is a Rails add-on that allows ActionMailer to send via the Mailgun API.
|
5
|
+
|
6
|
+
See [railgun-sample](https://github.com/pirogoeth/railgun-sample/) for examples of integrating Railgun with your Rails app.
|
7
|
+
|
8
|
+
|
9
|
+
## Table of Contents
|
10
|
+
|
11
|
+
- [Parameters](/docs/railgun/Parameters.md)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
Parameters
|
2
|
+
==========
|
3
|
+
|
4
|
+
When sending messages via Railgun, it is often useful to set options, headers, and variables
|
5
|
+
that should be added to the `POST` request against the messages endpoint.
|
6
|
+
|
7
|
+
|
8
|
+
## Options
|
9
|
+
|
10
|
+
See [Mailgun Docs | Sending](https://documentation.mailgun.com/en/latest/api-sending.html#sending) for available options.
|
11
|
+
|
12
|
+
---
|
13
|
+
|
14
|
+
To set options on a message:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# app/controllers/some_controller.rb
|
18
|
+
|
19
|
+
message = YourMailer.your_message(@args)
|
20
|
+
|
21
|
+
message.mailgun_options ||= {
|
22
|
+
"tracking-opens" => "true",
|
23
|
+
"tracking-clicks" => "htmlonly",
|
24
|
+
"tag" => "some,tags",
|
25
|
+
}
|
26
|
+
```
|
27
|
+
|
28
|
+
|
29
|
+
## Variables
|
30
|
+
|
31
|
+
See [Mailgun Docs | Attaching Data to Messages](https://documentation.mailgun.com/en/latest/user_manual.html#attaching-data-to-messages) for more information.
|
32
|
+
|
33
|
+
---
|
34
|
+
|
35
|
+
To set variables on a message:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# app/controllers/some_controller.rb
|
39
|
+
|
40
|
+
message = YourMailer.your_message(@args)
|
41
|
+
|
42
|
+
message.mailgun_variables ||= {
|
43
|
+
"user_info" => {"id" => "1", "name" => "tstark"},
|
44
|
+
}
|
45
|
+
```
|
46
|
+
|
47
|
+
|
48
|
+
## Headers
|
49
|
+
|
50
|
+
See [Mailgun Docs | Sending](https://documentation.mailgun.com/en/latest/api-sending.html#sending) for more information.
|
51
|
+
|
52
|
+
---
|
53
|
+
|
54
|
+
To set headers on a message *from a controller*:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# app/controllers/some_controller.rb
|
58
|
+
|
59
|
+
message = YourMailer.your_message(@args)
|
60
|
+
|
61
|
+
message.mailgun_headers ||= {
|
62
|
+
"X-Sent-From-Rails" => "true",
|
63
|
+
}
|
64
|
+
```
|
65
|
+
|
66
|
+
To set headers on a message *from a mailer*:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
# app/mailers/your_mailer.rb
|
70
|
+
|
71
|
+
class YourMailer < ApplicationMailer
|
72
|
+
# ...
|
73
|
+
|
74
|
+
def your_message(args)
|
75
|
+
headers({
|
76
|
+
"X-Sent-From-Rails" => "true",
|
77
|
+
})
|
78
|
+
|
79
|
+
mail to: "some-address@example.org", ...
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
```
|
data/lib/mailgun/client.rb
CHANGED
@@ -14,13 +14,20 @@ module Mailgun
|
|
14
14
|
api_host = 'api.mailgun.net',
|
15
15
|
api_version = 'v3',
|
16
16
|
ssl = true,
|
17
|
-
test_mode = false
|
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
|
18
27
|
|
19
28
|
endpoint = endpoint_generator(api_host, api_version, ssl)
|
20
|
-
|
21
|
-
|
22
|
-
password: api_key,
|
23
|
-
user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}")
|
29
|
+
RestClient.proxy = proxy_url
|
30
|
+
@http_client = RestClient::Resource.new(endpoint, rest_client_params)
|
24
31
|
@test_mode = test_mode
|
25
32
|
end
|
26
33
|
|
@@ -59,11 +66,13 @@ module Mailgun
|
|
59
66
|
# containing required parameters for the requested resource.
|
60
67
|
# @return [Mailgun::Response] A Mailgun::Response object.
|
61
68
|
def send_message(working_domain, data)
|
69
|
+
perform_data_validation(working_domain, data)
|
70
|
+
|
62
71
|
if test_mode? then
|
63
72
|
Mailgun::Client.deliveries << data
|
64
73
|
return Response.from_hash(
|
65
74
|
{
|
66
|
-
:body =>
|
75
|
+
:body => "{\"id\": \"test-mode-mail-#{SecureRandom.uuid}@localhost\", \"message\": \"Queued. Thank you.\"}",
|
67
76
|
:code => 200,
|
68
77
|
}
|
69
78
|
)
|
@@ -195,5 +204,17 @@ module Mailgun
|
|
195
204
|
CommunicationError.new(e.message)
|
196
205
|
end
|
197
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
|
198
219
|
end
|
199
220
|
end
|
@@ -101,7 +101,7 @@ module Mailgun
|
|
101
101
|
# Returns a String of the partial URI if the given url follows the regular API format
|
102
102
|
# Returns nil in other cases (e.g. when given nil, or an irrelevant url)
|
103
103
|
def extract_endpoint_from(url = nil)
|
104
|
-
URI.parse(url).path[
|
104
|
+
URI.parse(url).path[/\/v[\d]\/#{@domain}\/events\/(.+)/,1]
|
105
105
|
rescue URI::InvalidURIError
|
106
106
|
nil
|
107
107
|
end
|
@@ -34,6 +34,7 @@ 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
|
#
|
@@ -51,6 +52,7 @@ module Mailgun
|
|
51
52
|
rescue NoMethodError
|
52
53
|
api_message = "Unknown API error"
|
53
54
|
end
|
55
|
+
api_message = api_message + ' - Invalid Domain or API key' if api_message == FORBIDDEN
|
54
56
|
|
55
57
|
message = message || ''
|
56
58
|
message = message + ': ' + api_message
|
@@ -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,3 +1,4 @@
|
|
1
|
+
require 'mime/types'
|
1
2
|
require 'time'
|
2
3
|
|
3
4
|
module Mailgun
|
@@ -197,7 +198,9 @@ module Mailgun
|
|
197
198
|
# @param [Boolean] tracking Boolean true or false.
|
198
199
|
# @return [void]
|
199
200
|
def track_opens(mode)
|
200
|
-
|
201
|
+
value = bool_lookup(mode)
|
202
|
+
set_single('o:tracking-opens', value)
|
203
|
+
set_multi_simple('o:tracking', value)
|
201
204
|
end
|
202
205
|
|
203
206
|
# Deprecated: 'set_open_tracking' is deprecated. Please use 'track_opens' instead.
|
@@ -211,7 +214,9 @@ module Mailgun
|
|
211
214
|
# @param [String] mode True, False, or HTML (for HTML only tracking)
|
212
215
|
# @return [void]
|
213
216
|
def track_clicks(mode)
|
214
|
-
|
217
|
+
value = bool_lookup(mode)
|
218
|
+
set_single('o:tracking-clicks', value)
|
219
|
+
set_multi_simple('o:tracking', value)
|
215
220
|
end
|
216
221
|
|
217
222
|
# Depreciated: 'set_click_tracking. is deprecated. Please use 'track_clicks' instead.
|
@@ -269,8 +274,12 @@ module Mailgun
|
|
269
274
|
# @return [void]
|
270
275
|
def variable(name, data)
|
271
276
|
fail(Mailgun::ParameterError, 'Variable name must be specified') if name.to_s.empty?
|
272
|
-
|
273
|
-
|
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
|
274
283
|
end
|
275
284
|
|
276
285
|
# Add custom parameter to the message. A custom parameter is any parameter that
|
@@ -303,6 +312,38 @@ module Mailgun
|
|
303
312
|
message_id data
|
304
313
|
end
|
305
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
|
+
|
306
347
|
private
|
307
348
|
|
308
349
|
# Sets a single value in the message hash where "multidict" features are not needed.
|
@@ -342,6 +383,7 @@ module Mailgun
|
|
342
383
|
def bool_lookup(value)
|
343
384
|
return 'yes' if %w(true yes yep).include? value.to_s.downcase
|
344
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'
|
345
387
|
value
|
346
388
|
end
|
347
389
|
|
@@ -379,10 +421,17 @@ module Mailgun
|
|
379
421
|
def parse_address(address, vars)
|
380
422
|
return address unless vars.is_a? Hash
|
381
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
|
382
427
|
|
383
|
-
|
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
|
384
433
|
|
385
|
-
return "'#{full_name}' <#{address}>" if
|
434
|
+
return "'#{full_name}' <#{address}>" if full_name
|
386
435
|
address
|
387
436
|
end
|
388
437
|
|
@@ -402,6 +451,12 @@ module Mailgun
|
|
402
451
|
'Unable to access attachment file object.'
|
403
452
|
) unless attachment.respond_to?(:read)
|
404
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
|
+
|
405
460
|
unless filename.nil?
|
406
461
|
attachment.instance_variable_set :@original_filename, filename
|
407
462
|
attachment.instance_eval 'def original_filename; @original_filename; end'
|
data/lib/mailgun/suppressions.rb
CHANGED
@@ -157,7 +157,10 @@ module Mailgun
|
|
157
157
|
|
158
158
|
unsubscribe.each do |k, v|
|
159
159
|
# Hash values MUST be strings.
|
160
|
-
|
160
|
+
# However, unsubscribes contain an array of tags
|
161
|
+
if v.is_a? Array
|
162
|
+
unsubscribe[k] = v.map(&:to_s)
|
163
|
+
elsif !v.is_a? String
|
161
164
|
unsubscribe[k] = v.to_s
|
162
165
|
end
|
163
166
|
end
|
data/lib/mailgun/version.rb
CHANGED
@@ -46,7 +46,7 @@ module Mailgun
|
|
46
46
|
# Returns a Boolean of whether the webhook was created
|
47
47
|
def create(domain, action, url = '')
|
48
48
|
res = @client.post("domains/#{domain}/webhooks", id: action, url: url)
|
49
|
-
res.to_h['webhook']['url'] == url && res.to_h[message] == 'Webhook has been created'
|
49
|
+
res.to_h['webhook']['url'] == url && res.to_h['message'] == 'Webhook has been created'
|
50
50
|
end
|
51
51
|
alias_method :add, :create
|
52
52
|
alias_method :add_webhook, :create
|
data/lib/railgun/mailer.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'action_mailer'
|
2
|
+
require 'json'
|
2
3
|
require 'mailgun'
|
3
4
|
require 'rails'
|
4
5
|
require 'railgun/errors'
|
@@ -9,6 +10,9 @@ module Railgun
|
|
9
10
|
# Mailgun.
|
10
11
|
class Mailer
|
11
12
|
|
13
|
+
# List of the headers that will be ignored when copying headers from `mail.header_fields`
|
14
|
+
IGNORED_HEADERS = %w[ to from subject reply-to mime-version template ]
|
15
|
+
|
12
16
|
# [Hash] config ->
|
13
17
|
# Requires *at least* `api_key` and `domain` keys.
|
14
18
|
attr_accessor :config, :domain, :settings
|
@@ -23,7 +27,14 @@ module Railgun
|
|
23
27
|
raise Railgun::ConfigurationError.new("Config requires `#{k}` key", @config) unless @config.has_key?(k)
|
24
28
|
end
|
25
29
|
|
26
|
-
@mg_client = Mailgun::Client.new(
|
30
|
+
@mg_client = Mailgun::Client.new(
|
31
|
+
config[:api_key],
|
32
|
+
config[:api_host] || 'api.mailgun.net',
|
33
|
+
config[:api_version] || 'v3',
|
34
|
+
config[:api_ssl].nil? ? true : config[:api_ssl],
|
35
|
+
false,
|
36
|
+
config[:timeout],
|
37
|
+
)
|
27
38
|
@domain = @config[:domain]
|
28
39
|
|
29
40
|
# To avoid exception in mail gem v2.6
|
@@ -36,8 +47,11 @@ module Railgun
|
|
36
47
|
end
|
37
48
|
|
38
49
|
def deliver!(mail)
|
50
|
+
@mg_domain = set_mg_domain(mail)
|
51
|
+
mail[:domain] = nil if mail[:domain].present?
|
52
|
+
|
39
53
|
mg_message = Railgun.transform_for_mailgun(mail)
|
40
|
-
response = @mg_client.send_message(@
|
54
|
+
response = @mg_client.send_message(@mg_domain, mg_message)
|
41
55
|
|
42
56
|
if response.code == 200 then
|
43
57
|
mg_id = response.to_h['id']
|
@@ -47,7 +61,15 @@ module Railgun
|
|
47
61
|
end
|
48
62
|
|
49
63
|
def mailgun_client
|
50
|
-
@
|
64
|
+
@mg_client
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Set @mg_domain from mail[:domain] header if present, then remove it to prevent being sent.
|
70
|
+
def set_mg_domain(mail)
|
71
|
+
return mail[:domain].value if mail[:domain]
|
72
|
+
domain
|
51
73
|
end
|
52
74
|
|
53
75
|
end
|
@@ -58,24 +80,60 @@ module Railgun
|
|
58
80
|
# After prefixing them with the proper option type, they are added to
|
59
81
|
# the message hash where they will then be sent to the API as JSON.
|
60
82
|
#
|
83
|
+
# It is important to note that headers set in `mailgun_headers` on the message
|
84
|
+
# WILL overwrite headers set via `mail.headers()`.
|
85
|
+
#
|
61
86
|
# @param [Mail::Message] mail message to transform
|
62
87
|
#
|
63
88
|
# @return [Hash] transformed message hash
|
64
89
|
def transform_for_mailgun(mail)
|
65
90
|
message = build_message_object(mail)
|
66
91
|
|
67
|
-
# v:* attributes (variables)
|
68
|
-
mail.mailgun_variables.try(:each) do |k, v|
|
69
|
-
message["v:#{k}"] = v
|
70
|
-
end
|
71
|
-
|
72
92
|
# o:* attributes (options)
|
73
93
|
mail.mailgun_options.try(:each) do |k, v|
|
74
|
-
message["o:#{k}"] = v
|
94
|
+
message["o:#{k}"] = v.dup
|
75
95
|
end
|
76
96
|
|
97
|
+
# t:* attributes (options)
|
98
|
+
mail.mailgun_template_variables.try(:each) do |k, v|
|
99
|
+
message["t:#{k}"] = v.dup
|
100
|
+
end
|
101
|
+
|
102
|
+
# support for using ActionMailer's `headers()` inside of the mailer
|
103
|
+
# note: this will filter out parameters such as `from`, `to`, and so forth
|
104
|
+
# as they are accepted as POST parameters on the message endpoint.
|
105
|
+
|
106
|
+
msg_headers = Hash.new
|
107
|
+
|
77
108
|
# h:* attributes (headers)
|
78
|
-
|
109
|
+
|
110
|
+
# Let's set all of these headers on the [Mail::Message] so that
|
111
|
+
# the are created inside of a [Mail::Header] instance and processed there.
|
112
|
+
mail.headers(mail.mailgun_headers || {})
|
113
|
+
mail.header_fields.each do |field|
|
114
|
+
header = field.name.downcase
|
115
|
+
if msg_headers.include? header
|
116
|
+
msg_headers[header] = [msg_headers[header], field.value].flatten
|
117
|
+
else
|
118
|
+
msg_headers[header] = field.value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
msg_headers.each do |k, v|
|
123
|
+
if Railgun::Mailer::IGNORED_HEADERS.include? k.downcase
|
124
|
+
Rails.logger.debug("[railgun] ignoring header (using envelope instead): #{k}")
|
125
|
+
next
|
126
|
+
end
|
127
|
+
|
128
|
+
# Cover cases like `cc`, `bcc` where parameters are valid
|
129
|
+
# headers BUT they are submitted as separate POST params
|
130
|
+
# and already exist on the message because of the call to
|
131
|
+
# `build_message_object`.
|
132
|
+
if message.include? k.downcase
|
133
|
+
Rails.logger.debug("[railgun] ignoring header (already set): #{k}")
|
134
|
+
next
|
135
|
+
end
|
136
|
+
|
79
137
|
message["h:#{k}"] = v
|
80
138
|
end
|
81
139
|
|
@@ -84,7 +142,12 @@ module Railgun
|
|
84
142
|
|
85
143
|
# reject blank values
|
86
144
|
message.delete_if do |k, v|
|
87
|
-
|
145
|
+
return true if v.nil?
|
146
|
+
|
147
|
+
# if it's an array remove empty elements
|
148
|
+
v.delete_if { |i| i.respond_to?(:empty?) && i.empty? } if v.is_a?(Array)
|
149
|
+
|
150
|
+
v.respond_to?(:empty?) && v.empty?
|
88
151
|
end
|
89
152
|
|
90
153
|
return message
|
@@ -101,6 +164,7 @@ module Railgun
|
|
101
164
|
|
102
165
|
mb.from mail[:from]
|
103
166
|
mb.reply_to(mail[:reply_to].to_s) if mail[:reply_to].present?
|
167
|
+
mb.template(mail[:template].to_s) if mail[:template].present?
|
104
168
|
mb.subject mail.subject
|
105
169
|
mb.body_html extract_body_html(mail)
|
106
170
|
mb.body_text extract_body_text(mail)
|
@@ -120,6 +184,11 @@ module Railgun
|
|
120
184
|
end
|
121
185
|
end
|
122
186
|
|
187
|
+
# v:* attributes (variables)
|
188
|
+
mail.mailgun_variables.try(:each) do |name, value|
|
189
|
+
mb.variable(name, value)
|
190
|
+
end
|
191
|
+
|
123
192
|
return mb.message if mail.attachments.empty?
|
124
193
|
|
125
194
|
mail.attachments.each do |attach|
|
@@ -138,7 +207,7 @@ module Railgun
|
|
138
207
|
# @return [String]
|
139
208
|
def extract_body_html(mail)
|
140
209
|
begin
|
141
|
-
(mail
|
210
|
+
retrieve_html_part(mail).body.decoded || nil
|
142
211
|
rescue
|
143
212
|
nil
|
144
213
|
end
|
@@ -152,10 +221,33 @@ module Railgun
|
|
152
221
|
# @return [String]
|
153
222
|
def extract_body_text(mail)
|
154
223
|
begin
|
155
|
-
(mail
|
224
|
+
retrieve_text_part(mail).body.decoded || nil
|
156
225
|
rescue
|
157
226
|
nil
|
158
227
|
end
|
159
228
|
end
|
160
229
|
|
230
|
+
# Returns the mail object from the Mail::Message object if text part exists,
|
231
|
+
# (decomposing multipart into individual format if necessary)
|
232
|
+
# otherwise nil.
|
233
|
+
#
|
234
|
+
# @param [Mail::Message] mail message to transform
|
235
|
+
#
|
236
|
+
# @return [Mail::Message] mail message with its content-type = text/plain
|
237
|
+
def retrieve_text_part(mail)
|
238
|
+
return mail.text_part if mail.multipart?
|
239
|
+
(mail.mime_type =~ /^text\/plain$/i) && mail
|
240
|
+
end
|
241
|
+
|
242
|
+
# Returns the mail object from the Mail::Message object if html part exists,
|
243
|
+
# (decomposing multipart into individual format if necessary)
|
244
|
+
# otherwise nil.
|
245
|
+
#
|
246
|
+
# @param [Mail::Message] mail message to transform
|
247
|
+
#
|
248
|
+
# @return [Mail::Message] mail message with its content-type = text/html
|
249
|
+
def retrieve_html_part(mail)
|
250
|
+
return mail.html_part if mail.multipart?
|
251
|
+
(mail.mime_type =~ /^text\/html$/i) && mail
|
252
|
+
end
|
161
253
|
end
|
data/lib/railgun/message.rb
CHANGED
data/lib/railgun/railtie.rb
CHANGED
@@ -2,8 +2,9 @@ require 'railgun/mailer'
|
|
2
2
|
|
3
3
|
module Railgun
|
4
4
|
class Railtie < ::Rails::Railtie
|
5
|
-
|
6
|
-
|
5
|
+
ActiveSupport.on_load(:action_mailer) do
|
6
|
+
add_delivery_method :mailgun, Railgun::Mailer
|
7
|
+
ActiveSupport.run_load_hooks(:mailgun_mailer, Railgun::Mailer)
|
7
8
|
end
|
8
9
|
end
|
9
10
|
end
|