wj-mailgun-ruby 1.1.7

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