mailgun-ruby 1.1.2 → 1.2.4

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