mailgun-ruby 1.1.9 → 1.2.4
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/.travis.yml +6 -5
- data/Gemfile +1 -1
- data/README.md +24 -2
- data/docs/Domains.md +0 -0
- data/docs/Webhooks.md +0 -0
- data/docs/railgun/Overview.md +11 -0
- data/docs/railgun/Parameters.md +83 -0
- data/lib/mailgun/client.rb +12 -5
- data/lib/mailgun/events/events.rb +1 -1
- data/lib/mailgun/messages/batch_message.rb +1 -0
- data/lib/mailgun/messages/message_builder.rb +16 -5
- data/lib/mailgun/suppressions.rb +4 -1
- data/lib/mailgun/version.rb +1 -1
- data/lib/railgun/mailer.rb +58 -6
- 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/suppressions_spec.rb +18 -2
- data/spec/spec_helper.rb +3 -1
- data/spec/unit/events/events_spec.rb +19 -0
- data/spec/unit/messages/batch_message_spec.rb +1 -0
- data/spec/unit/messages/message_builder_spec.rb +36 -12
- data/spec/unit/messages/sample_data/unknown.type +0 -0
- data/spec/unit/{railgun_spec.rb → railgun/content_type_spec.rb} +0 -0
- data/spec/unit/railgun/mailer_spec.rb +242 -0
- data/vcr_cassettes/suppressions.yml +66 -15
- metadata +35 -31
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64d4a0d5c1b85d58db90763fc5dbcd0f813f29bf30b328fdda6b7a019fbeb445
|
4
|
+
data.tar.gz: 2ddef97a1b88cd9d45c5e2d1b41df3b61e7b3a09a5dcbe4c3b0a62191335aeed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18df9ff784b8c39376420fcebe0b16a195318e63b70e6b6f5fb6139fd4cbd276ef1647844de6fd12c1e272906862ddfcdc85bb59ab29460dee6e0e02ec872ee8
|
7
|
+
data.tar.gz: 25547234506d03d471ea3f3bbfb46eb6c10e104147f6fc7cbe3b3228b966d31b5a3e53f423554c22f45360c119c5c015659b819559ef8d664c7c5ac47be09d00
|
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.4'
|
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
File without changes
|
@@ -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,18 @@ 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
|
+
|
20
|
+
rest_client_params = {
|
21
|
+
user: 'api',
|
22
|
+
password: api_key,
|
23
|
+
user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}"
|
24
|
+
}
|
25
|
+
rest_client_params[:timeout] = timeout if timeout
|
18
26
|
|
19
27
|
endpoint = endpoint_generator(api_host, api_version, ssl)
|
20
|
-
@http_client = RestClient::Resource.new(endpoint,
|
21
|
-
user: 'api',
|
22
|
-
password: api_key,
|
23
|
-
user_agent: "mailgun-sdk-ruby/#{Mailgun::VERSION}")
|
28
|
+
@http_client = RestClient::Resource.new(endpoint, rest_client_params)
|
24
29
|
@test_mode = test_mode
|
25
30
|
end
|
26
31
|
|
@@ -59,6 +64,8 @@ module Mailgun
|
|
59
64
|
# containing required parameters for the requested resource.
|
60
65
|
# @return [Mailgun::Response] A Mailgun::Response object.
|
61
66
|
def send_message(working_domain, data)
|
67
|
+
fail ParameterError.new('Missing working domain', working_domain) unless working_domain
|
68
|
+
|
62
69
|
if test_mode? then
|
63
70
|
Mailgun::Client.deliveries << data
|
64
71
|
return Response.from_hash(
|
@@ -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
|
@@ -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,7 @@ module Mailgun
|
|
197
198
|
# @param [Boolean] tracking Boolean true or false.
|
198
199
|
# @return [void]
|
199
200
|
def track_opens(mode)
|
200
|
-
|
201
|
+
set_single('o:tracking-opens', bool_lookup(mode))
|
201
202
|
end
|
202
203
|
|
203
204
|
# Deprecated: 'set_open_tracking' is deprecated. Please use 'track_opens' instead.
|
@@ -211,7 +212,7 @@ module Mailgun
|
|
211
212
|
# @param [String] mode True, False, or HTML (for HTML only tracking)
|
212
213
|
# @return [void]
|
213
214
|
def track_clicks(mode)
|
214
|
-
|
215
|
+
set_single('o:tracking-clicks', bool_lookup(mode))
|
215
216
|
end
|
216
217
|
|
217
218
|
# Depreciated: 'set_click_tracking. is deprecated. Please use 'track_clicks' instead.
|
@@ -269,8 +270,12 @@ module Mailgun
|
|
269
270
|
# @return [void]
|
270
271
|
def variable(name, data)
|
271
272
|
fail(Mailgun::ParameterError, 'Variable name must be specified') if name.to_s.empty?
|
272
|
-
|
273
|
-
|
273
|
+
begin
|
274
|
+
jsondata = make_json data
|
275
|
+
set_single("v:#{name}", jsondata)
|
276
|
+
rescue Mailgun::ParameterError
|
277
|
+
set_single("v:#{name}", data)
|
278
|
+
end
|
274
279
|
end
|
275
280
|
|
276
281
|
# Add custom parameter to the message. A custom parameter is any parameter that
|
@@ -389,7 +394,7 @@ module Mailgun
|
|
389
394
|
full_name = "#{vars['first']} #{vars['last']}".strip
|
390
395
|
end
|
391
396
|
|
392
|
-
return "'#{full_name}' <#{address}>" if
|
397
|
+
return "'#{full_name}' <#{address}>" if full_name
|
393
398
|
address
|
394
399
|
end
|
395
400
|
|
@@ -409,6 +414,12 @@ module Mailgun
|
|
409
414
|
'Unable to access attachment file object.'
|
410
415
|
) unless attachment.respond_to?(:read)
|
411
416
|
|
417
|
+
if attachment.respond_to?(:path) && !attachment.respond_to?(:content_type)
|
418
|
+
mime_types = MIME::Types.type_for(attachment.path)
|
419
|
+
content_type = mime_types.empty? ? 'application/octet-stream' : mime_types[0].content_type
|
420
|
+
attachment.instance_eval "def content_type; '#{content_type}'; end"
|
421
|
+
end
|
422
|
+
|
412
423
|
unless filename.nil?
|
413
424
|
attachment.instance_variable_set :@original_filename, filename
|
414
425
|
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
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 ]
|
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
|
@@ -47,7 +58,7 @@ module Railgun
|
|
47
58
|
end
|
48
59
|
|
49
60
|
def mailgun_client
|
50
|
-
@
|
61
|
+
@mg_client
|
51
62
|
end
|
52
63
|
|
53
64
|
end
|
@@ -58,6 +69,9 @@ module Railgun
|
|
58
69
|
# After prefixing them with the proper option type, they are added to
|
59
70
|
# the message hash where they will then be sent to the API as JSON.
|
60
71
|
#
|
72
|
+
# It is important to note that headers set in `mailgun_headers` on the message
|
73
|
+
# WILL overwrite headers set via `mail.headers()`.
|
74
|
+
#
|
61
75
|
# @param [Mail::Message] mail message to transform
|
62
76
|
#
|
63
77
|
# @return [Hash] transformed message hash
|
@@ -66,16 +80,49 @@ module Railgun
|
|
66
80
|
|
67
81
|
# v:* attributes (variables)
|
68
82
|
mail.mailgun_variables.try(:each) do |k, v|
|
69
|
-
message["v:#{k}"] = v
|
83
|
+
message["v:#{k}"] = JSON.dump(v)
|
70
84
|
end
|
71
85
|
|
72
86
|
# o:* attributes (options)
|
73
87
|
mail.mailgun_options.try(:each) do |k, v|
|
74
|
-
message["o:#{k}"] = v
|
88
|
+
message["o:#{k}"] = v.dup
|
75
89
|
end
|
76
90
|
|
91
|
+
# support for using ActionMailer's `headers()` inside of the mailer
|
92
|
+
# note: this will filter out parameters such as `from`, `to`, and so forth
|
93
|
+
# as they are accepted as POST parameters on the message endpoint.
|
94
|
+
|
95
|
+
msg_headers = Hash.new
|
96
|
+
|
77
97
|
# h:* attributes (headers)
|
78
|
-
|
98
|
+
|
99
|
+
# Let's set all of these headers on the [Mail::Message] so that
|
100
|
+
# the are created inside of a [Mail::Header] instance and processed there.
|
101
|
+
mail.headers(mail.mailgun_headers || {})
|
102
|
+
mail.header_fields.each do |field|
|
103
|
+
header = field.name.downcase
|
104
|
+
if msg_headers.include? header
|
105
|
+
msg_headers[header] = [msg_headers[header], field.value].flatten
|
106
|
+
else
|
107
|
+
msg_headers[header] = field.value
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
msg_headers.each do |k, v|
|
112
|
+
if Railgun::Mailer::IGNORED_HEADERS.include? k.downcase
|
113
|
+
Rails.logger.debug("[railgun] ignoring header (using envelope instead): #{k}")
|
114
|
+
next
|
115
|
+
end
|
116
|
+
|
117
|
+
# Cover cases like `cc`, `bcc` where parameters are valid
|
118
|
+
# headers BUT they are submitted as separate POST params
|
119
|
+
# and already exist on the message because of the call to
|
120
|
+
# `build_message_object`.
|
121
|
+
if message.include? k.downcase
|
122
|
+
Rails.logger.debug("[railgun] ignoring header (already set): #{k}")
|
123
|
+
next
|
124
|
+
end
|
125
|
+
|
79
126
|
message["h:#{k}"] = v
|
80
127
|
end
|
81
128
|
|
@@ -84,7 +131,12 @@ module Railgun
|
|
84
131
|
|
85
132
|
# reject blank values
|
86
133
|
message.delete_if do |k, v|
|
87
|
-
|
134
|
+
return true if v.nil?
|
135
|
+
|
136
|
+
# if it's an array remove empty elements
|
137
|
+
v.delete_if { |i| i.respond_to?(:empty?) && i.empty? } if v.is_a?(Array)
|
138
|
+
|
139
|
+
v.respond_to?(:empty?) && v.empty?
|
88
140
|
end
|
89
141
|
|
90
142
|
return message
|