mailgun-ruby 1.1.2 → 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.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-env.yml.example +1 -1
  3. data/.travis.yml +8 -5
  4. data/Gemfile +1 -1
  5. data/README.md +77 -9
  6. data/{Domains.md → docs/Domains.md} +18 -0
  7. data/{Events.md → docs/Events.md} +0 -0
  8. data/{MessageBuilder.md → docs/MessageBuilder.md} +24 -5
  9. data/{Messages.md → docs/Messages.md} +3 -3
  10. data/{OptInHandler.md → docs/OptInHandler.md} +0 -0
  11. data/{Snippets.md → docs/Snippets.md} +21 -2
  12. data/docs/Suppressions.md +82 -0
  13. data/{Webhooks.md → docs/Webhooks.md} +1 -1
  14. data/docs/railgun/Overview.md +11 -0
  15. data/docs/railgun/Parameters.md +83 -0
  16. data/lib/mailgun/address.rb +5 -2
  17. data/lib/mailgun/client.rb +39 -8
  18. data/lib/mailgun/events/events.rb +40 -12
  19. data/lib/mailgun/messages/batch_message.rb +3 -2
  20. data/lib/mailgun/messages/message_builder.rb +99 -26
  21. data/lib/mailgun/suppressions.rb +273 -0
  22. data/lib/mailgun/version.rb +1 -1
  23. data/lib/mailgun/webhooks/webhooks.rb +1 -1
  24. data/lib/mailgun-ruby.rb +2 -1
  25. data/lib/railgun/attachment.rb +56 -0
  26. data/lib/railgun/errors.rb +27 -0
  27. data/lib/railgun/mailer.rb +237 -0
  28. data/lib/railgun/message.rb +17 -0
  29. data/lib/railgun/railtie.rb +10 -0
  30. data/lib/railgun.rb +8 -0
  31. data/mailgun.gemspec +12 -12
  32. data/spec/integration/email_validation_spec.rb +14 -0
  33. data/spec/integration/events_spec.rb +9 -1
  34. data/spec/integration/mailgun_spec.rb +0 -0
  35. data/spec/integration/suppressions_spec.rb +142 -0
  36. data/spec/spec_helper.rb +3 -1
  37. data/spec/unit/events/events_spec.rb +36 -2
  38. data/spec/unit/messages/batch_message_spec.rb +1 -0
  39. data/spec/unit/messages/message_builder_spec.rb +95 -19
  40. data/spec/unit/messages/sample_data/unknown.type +0 -0
  41. data/spec/unit/railgun/content_type_spec.rb +71 -0
  42. data/spec/unit/railgun/mailer_spec.rb +242 -0
  43. data/vcr_cassettes/email_validation.yml +57 -9
  44. data/vcr_cassettes/events.yml +48 -1
  45. data/vcr_cassettes/suppressions.yml +727 -0
  46. metadata +68 -36
@@ -0,0 +1,273 @@
1
+ require 'uri'
2
+
3
+ require 'mailgun/exceptions/exceptions'
4
+
5
+ module Mailgun
6
+
7
+ # The Mailgun::Suppressions object makes it easy to manage "suppressions"
8
+ # attached to an account. "Suppressions" means bounces, unsubscribes, and complaints.
9
+ class Suppressions
10
+
11
+ # @param [Mailgun::Client] client API client to use for requests
12
+ # @param [String] domain Domain name to use for the suppression endpoints.
13
+ def initialize(client, domain)
14
+ @client = client
15
+ @domain = domain
16
+
17
+ @paging_next = nil
18
+ @paging_prev = nil
19
+ end
20
+
21
+ ####
22
+ # Paging operations
23
+ ####
24
+
25
+ def next
26
+ response = get_from_paging @paging_next[:path], @paging_next[:params]
27
+ extract_paging response
28
+ response
29
+ end
30
+
31
+ def prev
32
+ response = get_from_paging @paging_prev[:path], @paging_prev[:params]
33
+ extract_paging response
34
+ response
35
+ end
36
+
37
+ ####
38
+ # Bounces Endpoint (/v3/:domain/bounces)
39
+ ####
40
+
41
+ def list_bounces(params = {})
42
+ response = @client.get("#{@domain}/bounces", params)
43
+ extract_paging response
44
+ response
45
+ end
46
+
47
+ def get_bounce(address)
48
+ @client.get("#{@domain}/bounces/#{address}", nil)
49
+ end
50
+
51
+ def create_bounce(params = {})
52
+ @client.post("#{@domain/bounces}", params)
53
+ end
54
+
55
+ # Creates multiple bounces on the Mailgun API.
56
+ # If a bounce does not have a valid structure, it will be added to a list of unsendable bounces.
57
+ # The list of unsendable bounces will be returned at the end of this operation.
58
+ #
59
+ # If more than 999 bounce entries are provided, the list will be split and recursive calls will be made.
60
+ #
61
+ # @param [Array] data Array of bounce hashes
62
+ # @return [Response] Mailgun API response
63
+ # @return [Array] Return values from recursive call for list split.
64
+ def create_bounces(data)
65
+ # `data` should be a list of hashes, with each hash containing *at least* an `address` key.
66
+ split_return = []
67
+ if data.length >= 1000 then
68
+ resp, resp_l = create_bounces data[999..-1]
69
+ split_return.push(resp)
70
+ split_return.concat(resp_l)
71
+ data = data[0..998]
72
+ elsif data.length == 0 then
73
+ return nil, []
74
+ end
75
+
76
+ valid = []
77
+ # Validate the bounces given
78
+ # NOTE: `data` could potentially be very large (1000 elements) so it is
79
+ # more efficient to pop from data and push into a different array as
80
+ # opposed to possibly copying the entire array to another array.
81
+ while not data.empty? do
82
+ bounce = data.pop
83
+ # Bounces MUST contain a `address` key.
84
+ if not bounce.include? :address then
85
+ raise Mailgun::ParameterError.new "Bounce MUST include a :address key: #{bounce}"
86
+ end
87
+
88
+ bounce.each do |k, v|
89
+ # Hash values MUST be strings.
90
+ if not v.is_a? String then
91
+ bounce[k] = v.to_s
92
+ end
93
+ end
94
+
95
+ valid.push bounce
96
+ end
97
+
98
+ response = @client.post("#{@domain}/bounces", valid.to_json, { "Content-Type" => "application/json" })
99
+ return response, split_return
100
+ end
101
+
102
+ def delete_bounce(address)
103
+ @client.delete("#{@domain}/bounces/#{address}")
104
+ end
105
+
106
+ def delete_all_bounces
107
+ @client.delete("#{@domain}/bounces")
108
+ end
109
+
110
+ ####
111
+ # Unsubscribes Endpoint (/v3/:domain/unsubscribes)
112
+ ####
113
+
114
+ def list_unsubscribes(params = {})
115
+ response = @client.get("#{@domain}/unsubscribes", params)
116
+ extract_paging response
117
+ response
118
+ end
119
+
120
+ def get_unsubscribe(address)
121
+ @client.get("#{@domain}/unsubscribes/#{address}")
122
+ end
123
+
124
+ def create_unsubscribe(params = {})
125
+ @client.post("#{@domain}/unsubscribes", params)
126
+ end
127
+
128
+ # Creates multiple unsubscribes on the Mailgun API.
129
+ # If an unsubscribe does not have a valid structure, it will be added to a list of unsendable unsubscribes.
130
+ # The list of unsendable unsubscribes will be returned at the end of this operation.
131
+ #
132
+ # If more than 999 unsubscribe entries are provided, the list will be split and recursive calls will be made.
133
+ #
134
+ # @param [Array] data Array of unsubscribe hashes
135
+ # @return [Response] Mailgun API response
136
+ # @return [Array] Return values from recursive call for list split.
137
+ def create_unsubscribes(data)
138
+ # `data` should be a list of hashes, with each hash containing *at least* an `address` key.
139
+ split_return = []
140
+ if data.length >= 1000 then
141
+ resp, resp_l = create_unsubscribes data[999..-1]
142
+ split_return.push(resp)
143
+ split_return.concat(resp_l)
144
+ data = data[0..998]
145
+ elsif data.length == 0 then
146
+ return nil, []
147
+ end
148
+
149
+ valid = []
150
+ # Validate the unsubscribes given
151
+ while not data.empty? do
152
+ unsubscribe = data.pop
153
+ # unsubscribes MUST contain a `address` key.
154
+ if not unsubscribe.include? :address then
155
+ raise Mailgun::ParameterError.new "Unsubscribe MUST include a :address key: #{unsubscribe}"
156
+ end
157
+
158
+ unsubscribe.each do |k, v|
159
+ # Hash values MUST be strings.
160
+ # 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
164
+ unsubscribe[k] = v.to_s
165
+ end
166
+ end
167
+
168
+ valid.push unsubscribe
169
+ end
170
+
171
+ response = @client.post("#{@domain}/unsubscribes", valid.to_json, { "Content-Type" => "application/json" })
172
+ return response, split_return
173
+ end
174
+
175
+ def delete_unsubscribe(address, params = {})
176
+ @client.delete("#{@domain}/unsubscribes/#{address}")
177
+ end
178
+
179
+ ####
180
+ # Complaints Endpoint (/v3/:domain/complaints)
181
+ ####
182
+
183
+ def list_complaints(params = {})
184
+ response = @client.get("#{@domain}/complaints", params)
185
+ extract_paging response
186
+ response
187
+ end
188
+
189
+ def get_complaint(address)
190
+ @client.get("#{@domain}/complaints/#{address}", nil)
191
+ end
192
+
193
+ def create_complaint(params = {})
194
+ @client.post("#{@domain}/complaints", params)
195
+ end
196
+
197
+ # Creates multiple complaints on the Mailgun API.
198
+ # If a complaint does not have a valid structure, it will be added to a list of unsendable complaints.
199
+ # The list of unsendable complaints will be returned at the end of this operation.
200
+ #
201
+ # If more than 999 complaint entries are provided, the list will be split and recursive calls will be made.
202
+ #
203
+ # @param [Array] data Array of complaint hashes
204
+ # @return [Response] Mailgun API response
205
+ # @return [Array] Return values from recursive call for list split.
206
+ def create_complaints(data)
207
+ # `data` should be a list of hashes, with each hash containing *at least* an `address` key.
208
+ split_return = []
209
+ if data.length >= 1000 then
210
+ resp, resp_l = create_complaints data[999..-1]
211
+ split_return.push(resp)
212
+ split_return.concat(resp_l)
213
+ data = data[0..998]
214
+ elsif data.length == 0 then
215
+ return nil, []
216
+ end
217
+
218
+ valid = []
219
+ # Validate the complaints given
220
+ while not data.empty? do
221
+ complaint = data.pop
222
+ # complaints MUST contain a `address` key.
223
+ if not complaint.include? :address then
224
+ raise Mailgun::ParameterError.new "Complaint MUST include a :address key: #{complaint}"
225
+ end
226
+
227
+ complaint.each do |k, v|
228
+ # Hash values MUST be strings.
229
+ if not v.is_a? String then
230
+ complaint[k] = v.to_s
231
+ end
232
+ end
233
+
234
+ valid.push complaint
235
+ end
236
+
237
+ response = @client.post("#{@domain}/complaints", valid.to_json, { "Content-Type" => "application/json" })
238
+ return response, split_return
239
+ end
240
+
241
+ def delete_complaint(address)
242
+ @client.delete("#{@domain}/complaints/#{address}")
243
+ end
244
+
245
+ private
246
+
247
+ def get_from_paging(uri, params = {})
248
+ @client.get(uri, params)
249
+ end
250
+
251
+ def extract_paging(response)
252
+ rhash = response.to_h
253
+ return nil unless rhash.include? "paging"
254
+
255
+ page_info = rhash["paging"]
256
+
257
+ # Build the `next` endpoint
258
+ page_next = URI.parse(page_info["next"])
259
+ @paging_next = {
260
+ :path => page_next.path[/\/v[\d](.+)/, 1],
261
+ :params => Hash[URI.decode_www_form page_next.query],
262
+ }
263
+
264
+ # Build the `prev` endpoint
265
+ page_prev = URI.parse(page_info["previous"])
266
+ @paging_prev = {
267
+ :path => page_prev.path[/\/v[\d](.+)/, 1],
268
+ :params => Hash[URI.decode_www_form page_prev.query],
269
+ }
270
+ end
271
+
272
+ end
273
+ end
@@ -1,4 +1,4 @@
1
1
  # It's the version. Yeay!
2
2
  module Mailgun
3
- VERSION = '1.1.2'
3
+ VERSION = '1.2.4'
4
4
  end
@@ -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 && 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/mailgun-ruby.rb CHANGED
@@ -1 +1,2 @@
1
- require 'mailgun'
1
+ require 'mailgun'
2
+ require 'railgun' if defined?(Rails)
@@ -0,0 +1,56 @@
1
+ module Railgun
2
+
3
+ class Attachment < StringIO
4
+
5
+ attr_reader :filename, :content_type, :path,
6
+ :original_filename, :overwritten_filename
7
+
8
+ def initialize(attachment, *args)
9
+ @path = ''
10
+ @inline = args.detect { |opt| opt[:inline] }
11
+
12
+ if @inline
13
+ @filename = attachment.cid
14
+ else
15
+ @filename = attachment.filename
16
+ end
17
+
18
+ @original_filename = @filename
19
+
20
+ if args.detect { |opt| opt[:filename] }
21
+ @filename = opt[:filename]
22
+ end
23
+
24
+ @overwritten_filename = @filename
25
+
26
+ @content_type = attachment.content_type.split(';')[0]
27
+
28
+ super attachment.body.decoded
29
+ end
30
+
31
+ def inline?
32
+ @inline
33
+ end
34
+
35
+ def is_original_filename
36
+ @original_filename == @overwritten_filename
37
+ end
38
+
39
+ def source_filename
40
+ @filename
41
+ end
42
+
43
+ def attach_to_message!(mb)
44
+ if mb.nil?
45
+ nil
46
+ end
47
+
48
+ if inline?
49
+ mb.add_inline_image self, @filename
50
+ else
51
+ mb.add_attachment self, @filename
52
+ end
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ module Railgun
2
+
3
+ class Error < StandardError
4
+
5
+ attr_reader :object
6
+
7
+ def initialize(message = nil, object = nil)
8
+ super(message)
9
+
10
+ @object = object
11
+ end
12
+ end
13
+
14
+ class ConfigurationError < Error
15
+ end
16
+
17
+ class InternalError < Error
18
+
19
+ attr_reader :source_exception
20
+
21
+ def initialize(source_exc, message = nil, object = nil)
22
+ super(message, object)
23
+
24
+ @source_exception = source_exc
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,237 @@
1
+ require 'action_mailer'
2
+ require 'json'
3
+ require 'mailgun'
4
+ require 'rails'
5
+ require 'railgun/errors'
6
+
7
+ module Railgun
8
+
9
+ # Railgun::Mailer is an ActionMailer provider for sending mail through
10
+ # Mailgun.
11
+ class Mailer
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
+
16
+ # [Hash] config ->
17
+ # Requires *at least* `api_key` and `domain` keys.
18
+ attr_accessor :config, :domain, :settings
19
+
20
+ # Initialize the Railgun mailer.
21
+ #
22
+ # @param [Hash] config Hash of config values, typically from `app_config.action_mailer.mailgun_config`
23
+ def initialize(config)
24
+ @config = config
25
+
26
+ [:api_key, :domain].each do |k|
27
+ raise Railgun::ConfigurationError.new("Config requires `#{k}` key", @config) unless @config.has_key?(k)
28
+ end
29
+
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
+ )
38
+ @domain = @config[:domain]
39
+
40
+ # To avoid exception in mail gem v2.6
41
+ @settings = { return_response: true }
42
+
43
+ if (@config[:fake_message_send] || false)
44
+ Rails.logger.info "NOTE: fake message sending has been enabled for mailgun-ruby!"
45
+ @mg_client.enable_test_mode!
46
+ end
47
+ end
48
+
49
+ def deliver!(mail)
50
+ mg_message = Railgun.transform_for_mailgun(mail)
51
+ response = @mg_client.send_message(@domain, mg_message)
52
+
53
+ if response.code == 200 then
54
+ mg_id = response.to_h['id']
55
+ mail.message_id = mg_id
56
+ end
57
+ response
58
+ end
59
+
60
+ def mailgun_client
61
+ @mg_client
62
+ end
63
+
64
+ end
65
+
66
+ module_function
67
+
68
+ # Performs a series of transformations on the `mailgun*` attributes.
69
+ # After prefixing them with the proper option type, they are added to
70
+ # the message hash where they will then be sent to the API as JSON.
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
+ #
75
+ # @param [Mail::Message] mail message to transform
76
+ #
77
+ # @return [Hash] transformed message hash
78
+ def transform_for_mailgun(mail)
79
+ message = build_message_object(mail)
80
+
81
+ # v:* attributes (variables)
82
+ mail.mailgun_variables.try(:each) do |k, v|
83
+ message["v:#{k}"] = JSON.dump(v)
84
+ end
85
+
86
+ # o:* attributes (options)
87
+ mail.mailgun_options.try(:each) do |k, v|
88
+ message["o:#{k}"] = v.dup
89
+ end
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
+
97
+ # h:* attributes (headers)
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
+
126
+ message["h:#{k}"] = v
127
+ end
128
+
129
+ # recipient variables
130
+ message['recipient-variables'] = mail.mailgun_recipient_variables.to_json if mail.mailgun_recipient_variables
131
+
132
+ # reject blank values
133
+ message.delete_if do |k, v|
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?
140
+ end
141
+
142
+ return message
143
+ end
144
+
145
+ # Acts on a Rails/ActionMailer message object and uses Mailgun::MessageBuilder
146
+ # to construct a new message.
147
+ #
148
+ # @param [Mail::Message] mail message to transform
149
+ #
150
+ # @returns [Hash] Message hash from Mailgun::MessageBuilder
151
+ def build_message_object(mail)
152
+ mb = Mailgun::MessageBuilder.new
153
+
154
+ mb.from mail[:from]
155
+ mb.reply_to(mail[:reply_to].to_s) if mail[:reply_to].present?
156
+ mb.subject mail.subject
157
+ mb.body_html extract_body_html(mail)
158
+ mb.body_text extract_body_text(mail)
159
+
160
+ [:to, :cc, :bcc].each do |rcpt_type|
161
+ addrs = mail[rcpt_type] || nil
162
+ case addrs
163
+ when String
164
+ # Likely a single recipient
165
+ mb.add_recipient rcpt_type.to_s, addrs
166
+ when Array
167
+ addrs.each do |addr|
168
+ mb.add_recipient rcpt_type.to_s, addr
169
+ end
170
+ when Mail::Field
171
+ mb.add_recipient rcpt_type.to_s, addrs.to_s
172
+ end
173
+ end
174
+
175
+ return mb.message if mail.attachments.empty?
176
+
177
+ mail.attachments.each do |attach|
178
+ attach = Attachment.new(attach, encoding: 'ascii-8bit', inline: attach.inline?)
179
+ attach.attach_to_message! mb
180
+ end
181
+
182
+ return mb.message
183
+ end
184
+
185
+ # Returns the decoded HTML body from the Mail::Message object if available,
186
+ # otherwise nil.
187
+ #
188
+ # @param [Mail::Message] mail message to transform
189
+ #
190
+ # @return [String]
191
+ def extract_body_html(mail)
192
+ begin
193
+ retrieve_html_part(mail).body.decoded || nil
194
+ rescue
195
+ nil
196
+ end
197
+ end
198
+
199
+ # Returns the decoded text body from the Mail::Message object if it is available,
200
+ # otherwise nil.
201
+ #
202
+ # @param [Mail::Message] mail message to transform
203
+ #
204
+ # @return [String]
205
+ def extract_body_text(mail)
206
+ begin
207
+ retrieve_text_part(mail).body.decoded || nil
208
+ rescue
209
+ nil
210
+ end
211
+ end
212
+
213
+ # Returns the mail object from the Mail::Message object if text part exists,
214
+ # (decomposing multipart into individual format if necessary)
215
+ # otherwise nil.
216
+ #
217
+ # @param [Mail::Message] mail message to transform
218
+ #
219
+ # @return [Mail::Message] mail message with its content-type = text/plain
220
+ def retrieve_text_part(mail)
221
+ return mail.text_part if mail.multipart?
222
+ (mail.mime_type =~ /^text\/plain$/i) && mail
223
+ end
224
+
225
+ # Returns the mail object from the Mail::Message object if html part exists,
226
+ # (decomposing multipart into individual format if necessary)
227
+ # otherwise nil.
228
+ #
229
+ # @param [Mail::Message] mail message to transform
230
+ #
231
+ # @return [Mail::Message] mail message with its content-type = text/html
232
+ def retrieve_html_part(mail)
233
+ return mail.html_part if mail.multipart?
234
+ (mail.mime_type =~ /^text\/html$/i) && mail
235
+ end
236
+
237
+ end
@@ -0,0 +1,17 @@
1
+ require 'mail'
2
+ require 'mailgun/messages/message_builder'
3
+ require 'railgun/attachment'
4
+ require 'railgun/errors'
5
+
6
+ module Mail
7
+
8
+ class Message
9
+
10
+ # Attributes to hold Mailgun-specific information
11
+ attr_accessor :mailgun_variables,
12
+ :mailgun_options,
13
+ :mailgun_recipient_variables,
14
+ :mailgun_headers
15
+
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ require 'railgun/mailer'
2
+
3
+ module Railgun
4
+ class Railtie < ::Rails::Railtie
5
+ ActiveSupport.on_load(:action_mailer) do
6
+ add_delivery_method :mailgun, Railgun::Mailer
7
+ ActiveSupport.run_load_hooks(:mailgun_mailer, Railgun::Mailer)
8
+ end
9
+ end
10
+ end
data/lib/railgun.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'railgun/railtie'
2
+ require 'railgun/attachment'
3
+ require 'railgun/errors'
4
+ require 'railgun/mailer'
5
+ require 'railgun/message'
6
+
7
+ module Railgun
8
+ end
data/mailgun.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.version = Mailgun::VERSION
10
10
  spec.homepage = 'http://www.mailgun.com'
11
11
  spec.platform = Gem::Platform::RUBY
12
- spec.license = 'Apache'
12
+ spec.license = 'Apache-2.0'
13
13
 
14
14
  spec.summary = "Mailgun's Official Ruby SDK"
15
15
  spec.description = "Mailgun's Official Ruby SDK for interacting with the Mailgun API."
@@ -22,16 +22,16 @@ Gem::Specification.new do |spec|
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.required_ruby_version = '>= 2.0.0'
26
-
27
- spec.add_development_dependency 'bundler', '~> 1.5'
28
- spec.add_development_dependency 'rspec', '~> 3.0'
29
- spec.add_development_dependency 'rake', '~> 10.0'
30
- spec.add_development_dependency 'webmock', '~> 1.22'
31
- spec.add_development_dependency 'pry', '~> 0.9'
32
- spec.add_development_dependency 'vcr', '~> 3.0'
33
- spec.add_development_dependency 'simplecov', '~> 0.11'
34
-
35
- spec.add_dependency 'rest-client', '~> 2.0'
25
+ spec.required_ruby_version = '>= 2.2.2'
26
+
27
+ spec.add_development_dependency 'bundler', '>= 1.16.2'
28
+ spec.add_development_dependency 'rspec', '~> 3.8.0'
29
+ spec.add_development_dependency 'rake', '~> 12.3.2'
30
+ spec.add_development_dependency 'webmock', '~> 3.4.2'
31
+ spec.add_development_dependency 'pry', '~> 0.11.3'
32
+ spec.add_development_dependency 'vcr', '~> 3.0.3'
33
+ spec.add_development_dependency 'simplecov', '~> 0.16.1'
34
+ spec.add_development_dependency 'rails'
35
+ spec.add_dependency 'rest-client', '>= 2.0.2'
36
36
 
37
37
  end