wj-mailgun-ruby 1.1.7

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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rubocop.yml +8 -0
  4. data/.rubocop_todo.yml +22 -0
  5. data/.ruby-env.yml.example +12 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +24 -0
  8. data/Gemfile +6 -0
  9. data/LICENSE +191 -0
  10. data/README.md +241 -0
  11. data/Rakefile +35 -0
  12. data/docs/Domains.md +54 -0
  13. data/docs/Events.md +46 -0
  14. data/docs/MessageBuilder.md +105 -0
  15. data/docs/Messages.md +107 -0
  16. data/docs/OptInHandler.md +103 -0
  17. data/docs/Snippets.md +526 -0
  18. data/docs/Suppressions.md +82 -0
  19. data/docs/Webhooks.md +40 -0
  20. data/lib/mailgun-ruby.rb +2 -0
  21. data/lib/mailgun.rb +39 -0
  22. data/lib/mailgun/address.rb +45 -0
  23. data/lib/mailgun/chains.rb +16 -0
  24. data/lib/mailgun/client.rb +199 -0
  25. data/lib/mailgun/domains/domains.rb +84 -0
  26. data/lib/mailgun/events/events.rb +120 -0
  27. data/lib/mailgun/exceptions/exceptions.rb +65 -0
  28. data/lib/mailgun/lists/opt_in_handler.rb +58 -0
  29. data/lib/mailgun/messages/batch_message.rb +125 -0
  30. data/lib/mailgun/messages/message_builder.rb +413 -0
  31. data/lib/mailgun/response.rb +62 -0
  32. data/lib/mailgun/suppressions.rb +270 -0
  33. data/lib/mailgun/version.rb +4 -0
  34. data/lib/mailgun/webhooks/webhooks.rb +101 -0
  35. data/lib/railgun.rb +8 -0
  36. data/lib/railgun/attachment.rb +56 -0
  37. data/lib/railgun/errors.rb +27 -0
  38. data/lib/railgun/mailer.rb +161 -0
  39. data/lib/railgun/message.rb +17 -0
  40. data/lib/railgun/railtie.rb +9 -0
  41. data/mailgun.gemspec +37 -0
  42. data/spec/integration/bounces_spec.rb +44 -0
  43. data/spec/integration/campaign_spec.rb +60 -0
  44. data/spec/integration/complaints_spec.rb +38 -0
  45. data/spec/integration/domains_spec.rb +39 -0
  46. data/spec/integration/email_validation_spec.rb +57 -0
  47. data/spec/integration/events_spec.rb +28 -0
  48. data/spec/integration/list_members_spec.rb +63 -0
  49. data/spec/integration/list_spec.rb +58 -0
  50. data/spec/integration/mailgun_spec.rb +121 -0
  51. data/spec/integration/messages/sample_data/mime.txt +38 -0
  52. data/spec/integration/routes_spec.rb +74 -0
  53. data/spec/integration/stats_spec.rb +15 -0
  54. data/spec/integration/suppressions_spec.rb +126 -0
  55. data/spec/integration/unsubscribes_spec.rb +42 -0
  56. data/spec/integration/webhook_spec.rb +54 -0
  57. data/spec/spec_helper.rb +45 -0
  58. data/spec/unit/connection/test_client.rb +99 -0
  59. data/spec/unit/events/events_spec.rb +50 -0
  60. data/spec/unit/lists/opt_in_handler_spec.rb +24 -0
  61. data/spec/unit/mailgun_spec.rb +127 -0
  62. data/spec/unit/messages/batch_message_spec.rb +131 -0
  63. data/spec/unit/messages/message_builder_spec.rb +584 -0
  64. data/spec/unit/messages/sample_data/mailgun_icon.png +0 -0
  65. data/spec/unit/messages/sample_data/mime.txt +38 -0
  66. data/spec/unit/messages/sample_data/rackspace_logo.jpg +0 -0
  67. data/vcr_cassettes/bounces.yml +175 -0
  68. data/vcr_cassettes/complaints.yml +175 -0
  69. data/vcr_cassettes/domains.todo.yml +42 -0
  70. data/vcr_cassettes/domains.yml +360 -0
  71. data/vcr_cassettes/email_validation.yml +167 -0
  72. data/vcr_cassettes/events.yml +108 -0
  73. data/vcr_cassettes/exceptions.yml +45 -0
  74. data/vcr_cassettes/list_members.yml +320 -0
  75. data/vcr_cassettes/mailing_list.todo.yml +43 -0
  76. data/vcr_cassettes/mailing_list.yml +390 -0
  77. data/vcr_cassettes/routes.yml +359 -0
  78. data/vcr_cassettes/send_message.yml +107 -0
  79. data/vcr_cassettes/stats.yml +44 -0
  80. data/vcr_cassettes/suppressions.yml +676 -0
  81. data/vcr_cassettes/unsubscribes.yml +191 -0
  82. data/vcr_cassettes/webhooks.yml +276 -0
  83. metadata +263 -0
@@ -0,0 +1,82 @@
1
+ Mailgun - Suppressions
2
+ ====================
3
+
4
+ This is the Mailgun Ruby *Suppressions* utilities.
5
+
6
+ The below assumes you've already installed the Mailgun Ruby SDK in to your
7
+ project. If not, go back to the master README for instructions. It currently supports
8
+ all calls except credentials.
9
+
10
+ ----
11
+
12
+ The Suppressions client lets you manage bounces, unsubscribes, and complaints for a
13
+ single domain.
14
+
15
+ You can view additional samples in the [suppressions_spec.rb](/spec/integration/suppressions_spec.rb)
16
+ or the Suppressions client API in [suppressions.rb](/lib/mailgun/suppressions.rb).
17
+
18
+
19
+ Usage
20
+ -----
21
+
22
+ To get an instance of the Suppressions client:
23
+
24
+ ```ruby
25
+ mg_client = Mailgun::Client.new('api_key')
26
+ supp_client = mg_client.suppressions('yourdomain.com')
27
+ ```
28
+
29
+ ----
30
+
31
+ To get a list of bounces, unsubscribes, and/or complaints:
32
+
33
+ ```ruby
34
+ supp_client.list_bounces
35
+ supp_client.list_unsubscribes
36
+ supp_client.list_complaints
37
+ ```
38
+
39
+ ----
40
+
41
+ To batch-add a set of bounces:
42
+
43
+ ```ruby
44
+ @addresses = <load or generate some addresses...>
45
+
46
+ bounces = []
47
+ @addresses.each do |addr|
48
+ bounces.push({
49
+ :address => addr,
50
+ :code => 500,
51
+ :error => 'some bounce because reasons',
52
+ })
53
+ end
54
+
55
+ response, addt_responses = @supp_client.create_bounces bounces
56
+ ```
57
+
58
+ `create_bounces`, `create_unsubscribes`, and `create_complaints` will all
59
+ return two values - first, a simple `Mailgun::Response` object. Second,
60
+ a list containing any `Mailgun::Response` objects created recursively, if over 998
61
+ bounces were provided to `create_*`.
62
+
63
+ ----
64
+
65
+ To delete bounces:
66
+
67
+ ```ruby
68
+ @addresses = <load addresses...>
69
+
70
+ @addresses.each do |addr|
71
+ @supp_client.delete_bounce addr
72
+ end
73
+ ```
74
+
75
+ Or, alternatively, to remove *all* bounces:
76
+
77
+ ```ruby
78
+ @supp_client.delete_all_bounces
79
+ ```
80
+
81
+ The `delete_*` methods are similar for `bounces`, `unsubscribe`, and `complaints` -
82
+ they all will return a `Mailgun::Response` object.
@@ -0,0 +1,40 @@
1
+ Mailgun - Webhooks
2
+ ====================
3
+
4
+ This is the Mailgun Ruby *Webhook* utilities.
5
+
6
+ The below assumes you've already installed the Mailgun Ruby SDK in to your
7
+ project. If not, go back to the master README for instructions. It currently supports
8
+ all calls except updating webhooks.
9
+
10
+ Usage - Webhooks
11
+ -----------------------
12
+
13
+ ```ruby
14
+ # First, instantiate the Mailgun Client with your API key
15
+ mg_client = Mailgun::Client.new('your-api-key')
16
+ hook = Mailgun::Webhooks.new(mg_client)
17
+
18
+ # Get a list webhooks for a domain.
19
+ hook.list 'my.perfect.domain'
20
+
21
+ # View a single webhook detail
22
+ hook.info 'my.perfect.domain', 'deliver'
23
+
24
+ # Add a single url for all webhooks
25
+ hook.create_all 'my.perfect.domain', 'https://the.webhook.url/'
26
+
27
+ # Add a url for a specific webhook
28
+ hook.create 'my.perfect.domain', 'deliver', 'https://the.webhook.url/'
29
+
30
+ # Remove a url for a specific webhook
31
+ hook.remove 'my.perfect.domain', 'deliver'
32
+
33
+ # Remove all webhooks for a domain
34
+ hook.remove 'my.perfect.domain'
35
+ ```
36
+
37
+ More Documentation
38
+ ------------------
39
+ See the official [Mailgun Domain Docs](https://documentation.mailgun.com/api-webhooks.html)
40
+ for more information
@@ -0,0 +1,2 @@
1
+ require 'mailgun'
2
+ require 'railgun' if defined?(Rails)
@@ -0,0 +1,39 @@
1
+ require 'tempfile'
2
+ require 'rest_client'
3
+ require 'yaml'
4
+ require 'json'
5
+
6
+ require 'mailgun/version'
7
+ require 'mailgun/client'
8
+ require 'mailgun/response'
9
+ require 'mailgun/chains'
10
+ require 'mailgun/address'
11
+ require 'mailgun/lists/opt_in_handler'
12
+ require 'mailgun/messages/batch_message'
13
+ require 'mailgun/messages/message_builder'
14
+ require 'mailgun/events/events'
15
+ require 'mailgun/exceptions/exceptions'
16
+ require 'mailgun/domains/domains'
17
+ require 'mailgun/webhooks/webhooks'
18
+
19
+ # Module for interacting with the sweet Mailgun API.
20
+ #
21
+ # See the Github documentation for full examples.
22
+ module Mailgun
23
+
24
+ class << self
25
+ attr_accessor :api_key,
26
+ :api_version,
27
+ :protocol,
28
+ :mailgun_host,
29
+ :test_mode,
30
+ :domain
31
+
32
+ def configure
33
+ yield self
34
+ true
35
+ end
36
+ alias_method :config, :configure
37
+ end
38
+
39
+ end
@@ -0,0 +1,45 @@
1
+ require 'mailgun/exceptions/exceptions'
2
+
3
+ module Mailgun
4
+
5
+ # Mailgun::Address is a simple interface to the Email Validation API.
6
+ class Address
7
+
8
+ # @param [String] api_key Mailgun API - public key
9
+ def initialize(api_key = "")
10
+ if api_key == "" then
11
+ fail ParameterError.new('Public API key is required for Mailgun::Address.initialize()', nil)
12
+ end
13
+
14
+ @api_key = api_key
15
+ @client = Mailgun::Client.new(api_key = api_key)
16
+ end
17
+
18
+ # Given an arbitrary address, validates it based on defined checks.
19
+ #
20
+ # @param [String] address Email address to validate (max 512 chars.)
21
+ def validate(address)
22
+ res = @client.get "address/validate", {:address => address}
23
+ return res.to_h!
24
+ end
25
+
26
+ # Parses a delimiter separated list of email addresses into two lists:
27
+ # parsed addresses and unparsable portions. The parsed addresses are a
28
+ # list of addresses that are syntactically valid (and optionally have
29
+ # DNS and ESP specific grammar checks) the unparsable list is a list
30
+ # of characters sequences that the parser was not able to understand.
31
+ # These often align with invalid email addresses, but not always.
32
+ # Delimiter characters are comma (,) and semicolon (;).
33
+ #
34
+ # @param [Array] addresses Addresses to parse
35
+ # @param [TrueClass|FalseClass] syntax_only Perform only syntax checks
36
+ def parse(addresses, syntax_only = true)
37
+ validate_addrs = addresses.join(";")
38
+
39
+ res = @client.get "address/parse", {:addresses => validate_addrs,
40
+ :syntax_only => syntax_only.to_s}
41
+ return res.to_h!
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,16 @@
1
+ module Mailgun
2
+
3
+ # Public constants used throughout
4
+ class Chains
5
+
6
+ # maximum campaign ids per message
7
+ MAX_CAMPAIGN_IDS = 3
8
+
9
+ # maximum tags per message
10
+ MAX_TAGS = 3
11
+
12
+ # maximum recipients per message or batch
13
+ MAX_RECIPIENTS = 1000
14
+
15
+ end
16
+ end
@@ -0,0 +1,199 @@
1
+ require 'mailgun/chains'
2
+ require 'mailgun/suppressions'
3
+ require 'mailgun/exceptions/exceptions'
4
+
5
+ module Mailgun
6
+ # A Mailgun::Client object is used to communicate with the Mailgun API. It is a
7
+ # wrapper around RestClient so you don't have to worry about the HTTP aspect
8
+ # of communicating with our API.
9
+ #
10
+ # See the Github documentation for full examples.
11
+ class Client
12
+
13
+ def initialize(api_key = Mailgun.api_key,
14
+ api_host = 'api.mailgun.net',
15
+ api_version = 'v3',
16
+ ssl = true,
17
+ test_mode = false)
18
+
19
+ 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}")
24
+ @test_mode = test_mode
25
+ end
26
+
27
+ # Enable test mode
28
+ #
29
+ # Prevents sending of any messages.
30
+ def enable_test_mode!
31
+ @test_mode = true
32
+ end
33
+
34
+ # Disable test mode
35
+ #
36
+ # Reverts the test_mode flag and allows the client to send messages.
37
+ def disable_test_mode!
38
+ @test_mode = false
39
+ end
40
+
41
+ # Client is in test mode?
42
+ #
43
+ # @return [Boolean] Is the client set in test mode?
44
+ def test_mode?
45
+ @test_mode
46
+ end
47
+
48
+ # Provides a store of all the emails sent in test mode so you can check them.
49
+ #
50
+ # @return [Hash]
51
+ def self.deliveries
52
+ @@deliveries ||= []
53
+ end
54
+
55
+ # Simple Message Sending
56
+ #
57
+ # @param [String] working_domain This is the domain you wish to send from.
58
+ # @param [Hash] data This should be a standard Hash
59
+ # containing required parameters for the requested resource.
60
+ # @return [Mailgun::Response] A Mailgun::Response object.
61
+ def send_message(working_domain, data)
62
+ if test_mode? then
63
+ Mailgun::Client.deliveries << data
64
+ return Response.from_hash(
65
+ {
66
+ :body => '{"id": "test-mode-mail@localhost", "message": "Queued. Thank you."}',
67
+ :code => 200,
68
+ }
69
+ )
70
+ end
71
+
72
+ case data
73
+ when Hash
74
+ # Remove nil values from the data hash
75
+ # Submitting nils to the API will likely cause an error.
76
+ # See also: https://github.com/mailgun/mailgun-ruby/issues/32
77
+ data = data.select { |k, v| v != nil }
78
+
79
+ if data.key?(:message)
80
+ if data[:message].is_a?(String)
81
+ data[:message] = convert_string_to_file(data[:message])
82
+ end
83
+ return post("#{working_domain}/messages.mime", data)
84
+ end
85
+ post("#{working_domain}/messages", data)
86
+ when MessageBuilder
87
+ post("#{working_domain}/messages", data.message)
88
+ else
89
+ fail ParameterError.new('Unknown data type for data parameter.', data)
90
+ end
91
+ end
92
+
93
+ # Generic Mailgun POST Handler
94
+ #
95
+ # @param [String] resource_path This is the API resource you wish to interact
96
+ # with. Be sure to include your domain, where necessary.
97
+ # @param [Hash] data This should be a standard Hash
98
+ # containing required parameters for the requested resource.
99
+ # @param [Hash] headers Additional headers to pass to the resource.
100
+ # @return [Mailgun::Response] A Mailgun::Response object.
101
+ def post(resource_path, data, headers = {})
102
+ response = @http_client[resource_path].post(data, headers)
103
+ Response.new(response)
104
+ rescue => err
105
+ raise communication_error err
106
+ end
107
+
108
+ # Generic Mailgun GET Handler
109
+ #
110
+ # @param [String] resource_path This is the API resource you wish to interact
111
+ # with. Be sure to include your domain, where necessary.
112
+ # @param [Hash] params This should be a standard Hash
113
+ # containing required parameters for the requested resource.
114
+ # @param [String] accept Acceptable Content-Type of the response body.
115
+ # @return [Mailgun::Response] A Mailgun::Response object.
116
+ def get(resource_path, params = nil, accept = '*/*')
117
+ if params
118
+ response = @http_client[resource_path].get(params: params, accept: accept)
119
+ else
120
+ response = @http_client[resource_path].get(accept: accept)
121
+ end
122
+ Response.new(response)
123
+ rescue => err
124
+ raise communication_error err
125
+ end
126
+
127
+ # Generic Mailgun PUT Handler
128
+ #
129
+ # @param [String] resource_path This is the API resource you wish to interact
130
+ # with. Be sure to include your domain, where necessary.
131
+ # @param [Hash] data This should be a standard Hash
132
+ # containing required parameters for the requested resource.
133
+ # @return [Mailgun::Response] A Mailgun::Response object.
134
+ def put(resource_path, data)
135
+ response = @http_client[resource_path].put(data)
136
+ Response.new(response)
137
+ rescue => err
138
+ raise communication_error err
139
+ end
140
+
141
+ # Generic Mailgun DELETE Handler
142
+ #
143
+ # @param [String] resource_path This is the API resource you wish to interact
144
+ # with. Be sure to include your domain, where necessary.
145
+ # @return [Mailgun::Response] A Mailgun::Response object.
146
+ def delete(resource_path)
147
+ response = @http_client[resource_path].delete
148
+ Response.new(response)
149
+ rescue => err
150
+ raise communication_error err
151
+ end
152
+
153
+ # Constructs a Suppressions client for the given domain.
154
+ #
155
+ # @param [String] domain Domain which suppressions requests will be made for
156
+ # @return [Mailgun::Suppressions]
157
+ def suppressions(domain)
158
+ Suppressions.new(self, domain)
159
+ end
160
+
161
+ private
162
+
163
+ # Converts MIME string to file for easy uploading to API
164
+ #
165
+ # @param [String] string MIME string to post to API
166
+ # @return [File] File object
167
+ def convert_string_to_file(string)
168
+ file = Tempfile.new('MG_TMP_MIME')
169
+ file.write(string)
170
+ file.rewind
171
+ file
172
+ end
173
+
174
+ # Generates the endpoint URL to for the API. Allows overriding
175
+ # API endpoint, API versions, and toggling SSL.
176
+ #
177
+ # @param [String] api_host URL endpoint the library will hit
178
+ # @param [String] api_version The version of the API to hit
179
+ # @param [Boolean] ssl True, SSL. False, No SSL.
180
+ # @return [string] concatenated URL string
181
+ def endpoint_generator(api_host, api_version, ssl)
182
+ ssl ? scheme = 'https' : scheme = 'http'
183
+ if api_version
184
+ "#{scheme}://#{api_host}/#{api_version}"
185
+ else
186
+ "#{scheme}://#{api_host}"
187
+ end
188
+ end
189
+
190
+ # Raises CommunicationError and stores response in it if present
191
+ #
192
+ # @param [StandardException] e upstream exception object
193
+ def communication_error(e)
194
+ return CommunicationError.new(e.message, e.response) if e.respond_to? :response
195
+ CommunicationError.new(e.message)
196
+ end
197
+
198
+ end
199
+ end
@@ -0,0 +1,84 @@
1
+ require 'mailgun/exceptions/exceptions'
2
+
3
+ module Mailgun
4
+
5
+ # A Mailgun::Domains object is a simple CRUD interface to Mailgun Domains.
6
+ # Uses Mailgun
7
+ class Domains
8
+
9
+ # Public: creates a new Mailgun::Domains instance.
10
+ # Defaults to Mailgun::Client
11
+ def initialize(client = Mailgun::Client.new)
12
+ @client = client
13
+ end
14
+
15
+ # Public: Get Domains
16
+ #
17
+ # limit - [Integer] Maximum number of records to return. (100 by default)
18
+ # skip - [Integer] Number of records to skip. (0 by default)
19
+ #
20
+ # Returns [Array] A list of domains (hash)
21
+ def list(options = {})
22
+ @client.get('domains', options).to_h['items']
23
+ end
24
+ alias_method :get_domains, :list
25
+
26
+ # Public: Get domain information
27
+ #
28
+ # domain - [String] Domain name to lookup
29
+ #
30
+ # Returns [Hash] Information on the requested domains.
31
+ def info(domain)
32
+ fail(ParameterError, 'No domain given to find on Mailgun', caller) unless domain
33
+ @client.get("domains/#{domain}").to_h!
34
+ end
35
+ alias_method :get, :info
36
+ alias_method :get_domain, :info
37
+
38
+ # Public: Verify domain, update domain records
39
+ # Unknown status - this is not in the current Mailgun API
40
+ # Do no rely on this being available in future releases.
41
+ #
42
+ # domain - [String] Domain name
43
+ #
44
+ # Returns [Hash] Information on the updated/verified domains
45
+ def verify(domain)
46
+ fail(ParameterError, 'No domain given to verify on Mailgun', caller) unless domain
47
+ @client.put("domains/#{domain}/verify", nil).to_h!
48
+ end
49
+ alias_method :verify_domain, :verify
50
+
51
+ # Public: Add domain
52
+ #
53
+ # domain - [String] Name of the domain (ex. domain.com)
54
+ # options - [Hash] of
55
+ # smtp_password - [String] Password for SMTP authentication
56
+ # spam_action - [String] disabled or tag
57
+ # Disable, no spam filtering will occur for inbound messages.
58
+ # Tag, messages will be tagged wtih a spam header. See Spam Filter.
59
+ # wildcard - [Boolean] true or false Determines whether the domain will accept email for sub-domains.
60
+ #
61
+ # Returns [Hash] of created domain
62
+ def create(domain, options = {})
63
+ fail(ParameterError, 'No domain given to add on Mailgun', caller) unless domain
64
+ options = { smtp_password: nil, spam_action: 'disabled', wildcard: false }.merge(options)
65
+ options[:name] = domain
66
+ @client.post('domains', options).to_h
67
+ end
68
+ alias_method :add, :create
69
+ alias_method :add_domain, :create
70
+
71
+ # Public: Delete Domain
72
+ #
73
+ # domain - [String] domain name to delete (ex. domain.com)
74
+ #
75
+ # Returns [Boolean] if successful or not
76
+ def remove(domain)
77
+ fail(ParameterError, 'No domain given to remove on Mailgun', caller) unless domain
78
+ @client.delete("domains/#{domain}").to_h['message'] == 'Domain has been deleted'
79
+ end
80
+ alias_method :delete, :remove
81
+ alias_method :delete_domain, :remove
82
+
83
+ end
84
+ end