mailgun 0.0.3 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,7 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ startup.rb
19
+ Guardfile
20
+ .DS_Store
21
+ lib/startup.rb
data/Gemfile CHANGED
@@ -1,9 +1,9 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem "rest-client"
4
-
5
3
  group :development do
6
4
  gem "rspec"
5
+ gem "guard"
6
+ gem 'simplecov', :require => false, :group => :test
7
7
  end
8
8
 
9
9
  # Specify your gem's dependencies in mailgun.gemspec
data/README.md CHANGED
@@ -6,30 +6,133 @@ The official gem repo is at https://github.com/Bushido/mailgun
6
6
 
7
7
  Mailgun exposes the following resources:
8
8
 
9
+ * Mailing Lists
10
+ * Mailing List Members
11
+ * Mailboxes
9
12
  * Routes
10
13
  * Log
11
14
  * Stats
12
15
  * Messages
13
- * Mailboxes
16
+ * Bounces
17
+ * Unsubscribes
18
+ * Complaints
19
+
20
+ Currently the gem only exposes the Mailbox and Routes APIs, but patches are welcome (and easy!).
21
+
22
+ ActionMailer
23
+ ============
24
+
25
+ This gem is unnecessary if you'd like to simply hook up Mailgun to Rails' Action Mailer. Just add the below to your Configuration.
14
26
 
15
- Currently the gem only exposes the Mailbox API, but patches are welcome (and easy!).
27
+ ActionMailer::Base.smtp_settings = {
28
+ :port => 587,
29
+ :address => 'smtp.mailgun.org',
30
+ :user_name => 'postmaster@your.mailgun.domain',
31
+ :password => 'mailgun-smtp-password',
32
+ :domain => 'your.mailgun.domain',
33
+ :authentication => :plain,
34
+ }
35
+ ActionMailer::Base.delivery_method = :smtp
16
36
 
17
37
  Usage
18
38
  =====
19
39
  We mimic the ActiveRecord-style interface.
20
40
 
41
+
42
+ Configuration:
43
+
21
44
  # Initialize your Mailgun object:
45
+ Mailgun.configure do |config|
46
+ config.api_key = 'your-api-key'
47
+ config.domain = 'your-mailgun-domain'
48
+ end
49
+
50
+ @mailgun = Mailgun()
51
+
52
+ # or alternatively:
22
53
  @mailgun = Mailgun(:api_key => 'your-api-key')
23
54
 
55
+
56
+ Mailing Lists:
57
+
58
+ # Create a mailing list
59
+ @mailgun.lists.create "devs@your.mailgun.domain"
60
+
61
+ # List all Mailing lists
62
+ @mailgun.lists.all
63
+
64
+ # Find a mailing list
65
+ @mailgun.lists.find "devs@your.mailgun.domain"
66
+
67
+ # Update a mailing list
68
+ @mailgun.lists.update("devs@your.mailgun.domain", "developers@your.mailgun.domain", "Developers", "Develepor Mailing List")
69
+
70
+ # Delete a mailing list
71
+ @mailgun.lists.delete("developers@your.mailgun.domain")
72
+
73
+ Mailing List Members:
74
+
75
+ # List all members within a mailing list
76
+ @mailgun.list_members.list "devs@your.mailgun.domain"
77
+
78
+ # Find a particular member in a list
79
+ @mailgun.list_members.find "devs@your.mailgun.domain", "bond@mi6.co.uk"
80
+
81
+ # Add a member to a list
82
+ @mailgun.list_members.add "devs@your.mailgun.domain", "Q@mi6.co.uk"
83
+
84
+ # Update a member on a list
85
+ @mailgun.list_members.update "devs@your.mailgun.domain", "Q@mi6.co.uk", "Q", {:gender => 'male'}.to_json, :subscribed => 'no')
86
+
87
+ # Remove a member from a list
88
+ @mailgun.list_members.remove "devs@your.mailgun.domain", "M@mi6.co.uk"
89
+
90
+ Mailboxes:
91
+
24
92
  # Create a mailbox
25
- @mailgun.mailbox.create "new-mailbox@your-domain.com", "password"
93
+ @mailgun.mailboxes.create "new-mailbox@your-domain.com", "password"
26
94
 
27
95
  # List all mailboxes that belong to a domain
28
- @mailgun.mailboxes.list domain.com"
96
+ @mailgun.mailboxes.list "domain.com"
29
97
 
30
98
  # Destroy a mailbox (queue bond-villian laughter)
31
99
  # "I'm sorry Bond, it seems your mailbox will be... destroyed!"
32
- @mailbox.mailboxes.destroy "bond@mi5.co.uk"
100
+ @mailbox.mailboxes.destroy "bond@mi6.co.uk"
101
+
102
+
103
+ Routes:
104
+
105
+ # Initialize your Mailgun object:
106
+ @mailgun = Mailgun(:api_key => 'your-api-key')
107
+
108
+ # Create a route
109
+ # Give it a human-readable description for later, a priority
110
+ # filters, and actions
111
+ @mailgun.routes.create "Description for the new route", 1,
112
+ [:match_recipient, "apowers@mi5.co.uk"],
113
+ [[:forward, "http://my-site.com/incoming-mail-route"],
114
+ [:stop]]
115
+
116
+ # List all routes that belong to a domain
117
+ # limit the query to 100 routes starting from 0
118
+ @mailgun.routes.list 100, 0
119
+
120
+ # Get the details of a route via its id
121
+ @mailgun.routes.find "4e97c1b2ba8a48567f007fb6"
122
+
123
+ # Update a route via its id
124
+ # (all keys are optional)
125
+ @mailgun.routes.update "4e97c1b2ba8a48567f007fb6", {
126
+ :priority => 2,
127
+ :filter => [:match_header, :subject, "*.support"],
128
+ :actions => [[:forward, "http://new-site.com/incoming-emails"]]
129
+ }
130
+
131
+ # Destroy a route via its id
132
+ @mailbox.routes.destroy "4e97c1b2ba8a48567f007fb6"
133
+
134
+ Supported route filters are: `:match_header`, `:match_recipient`, and `:catch_all`
135
+ Supported route actions are: `:forward`, and `:stop`
33
136
 
34
137
  Making Your Changes
35
138
  ===================
@@ -41,18 +144,28 @@ Making Your Changes
41
144
  * After making your changes, be sure to run the Mailgun RSpec specs to make sure everything works.
42
145
  * Submit your change as a Pull Request and update the GitHub issue to let us know it is ready for review.
43
146
 
147
+
148
+ TODO
149
+ =========
150
+
151
+ * Mailgun() is overwriting api key. api key is not persisting
152
+ * Add skip and limit functionality
153
+ * Distinguish failed in logs
154
+ * Distinguish delivered in logs
155
+ * Tracking?
156
+ * Stats?
157
+ * Campaign?
158
+
44
159
  Authors
45
160
  =======
46
161
 
47
162
  * Akash Manohar J (akash@akash.im)
163
+ * Scott Carleton (@scotterc) - for new functionality and major improvements.
48
164
  * Sean Grove (sean@gobushido.com)
165
+
49
166
 
50
- Thanks
51
- ======
52
- Huge thanks to the Mailgun guys for such an amazing service! No time spent on mailservers == way more time spent drinking!
53
-
54
- License & Copyright
167
+ License
55
168
  ===================
56
- Released under the MIT license. See LICENSE for more details.
169
+ Released under the MIT license by CloudFuji. See LICENSE for more details.
57
170
 
58
- All copyright Bushido Inc. 2011
171
+ This is a fork of he Cloudfuji/mailgun repo.
data/lib/mailgun/base.rb CHANGED
@@ -1,11 +1,5 @@
1
1
  module Mailgun
2
2
  class Base
3
- attr_accessor :api_key,
4
- :api_version,
5
- :protocol,
6
- :mailgun_host,
7
- :use_test_mode
8
-
9
3
  # Options taken from
10
4
  # http://documentation.mailgun.net/quickstart.html#authentication
11
5
  # * Mailgun host - location of mailgun api servers
@@ -13,22 +7,86 @@ module Mailgun
13
7
  # * API key and version
14
8
  # * Test mode - if enabled, doesn't actually send emails (see http://documentation.mailgun.net/user_manual.html#sending-in-test-mode)
15
9
  def initialize(options)
16
- @mailgun_host = options.fetch(:mailgun_host) {"api.mailgun.net"}
17
- @protocol = options.fetch(:protocol) { "https" }
18
- @api_version = options.fetch(:api_version) { "v2" }
19
- @test_mode = options.fetch(:test_mode) { false }
20
-
21
- @api_key = options.fetch(:api_key) { raise ArgumentError(":api_key is a required argument to initialize Mailgun") }
10
+ Mailgun.mailgun_host = options.fetch(:mailgun_host) {"api.mailgun.net"}
11
+ Mailgun.protocol = options.fetch(:protocol) { "https" }
12
+ Mailgun.api_version = options.fetch(:api_version) { "v2" }
13
+ Mailgun.test_mode = options.fetch(:test_mode) { false }
14
+ Mailgun.api_key = options.fetch(:api_key) { raise ArgumentError.new(":api_key is a required argument to initialize Mailgun") if Mailgun.api_key.nil?}
22
15
  end
23
16
 
24
17
  # Returns the base url used in all Mailgun API calls
25
18
  def base_url
26
- "#{@protocol}://api:#{api_key}@#{mailgun_host}/#{api_version}"
19
+ "#{Mailgun.protocol}://api:#{Mailgun.api_key}@#{Mailgun.mailgun_host}/#{Mailgun.api_version}"
27
20
  end
28
21
 
29
22
  # Returns an instance of Mailgun::Mailbox configured for the current API user
30
23
  def mailboxes
31
24
  @mailboxes ||= Mailgun::Mailbox.new(self)
32
25
  end
26
+
27
+ def routes
28
+ @routes ||= Mailgun::Route.new(self)
29
+ end
30
+
31
+ def bounces
32
+ @bounces ||= Mailgun::Bounce.new(self)
33
+ end
34
+
35
+ def unsubscribes
36
+ @unsubscribes ||= Mailgun::Unsubscribe.new(self)
37
+ end
38
+
39
+ def complaints
40
+ @complaints ||= Mailgun::Complaint.new(self)
41
+ end
42
+
43
+ def log
44
+ @log ||= Mailgun::Log.new(self)
45
+ end
46
+
47
+ def lists
48
+ @lists ||= Mailgun::List.new(self)
49
+ end
50
+
51
+ def list_members
52
+ @list_members ||= Mailgun::List::Member.new(self)
53
+ end
54
+ end
55
+
56
+
57
+ # Submits the API call to the Mailgun server
58
+ def self.submit(method, url, parameters={})
59
+ begin
60
+ return JSON(RestClient.send(method, url, parameters))
61
+ rescue => e
62
+ error_message = nil
63
+ if e.respond_to? :http_body
64
+ begin
65
+ error_message = JSON(e.http_body)["message"]
66
+ rescue
67
+ raise e
68
+ end
69
+ raise Mailgun::Error.new(error_message)
70
+ end
71
+ raise e
72
+ end
73
+ end
74
+
75
+ #
76
+ # @TODO Create root module to give this a better home
77
+ #
78
+ class << self
79
+ attr_accessor :api_key,
80
+ :api_version,
81
+ :protocol,
82
+ :mailgun_host,
83
+ :test_mode,
84
+ :domain
85
+
86
+ def configure
87
+ yield self
88
+ true
89
+ end
90
+ alias :config :configure
33
91
  end
34
92
  end
@@ -0,0 +1,35 @@
1
+ module Mailgun
2
+ class Bounce
3
+ # Used internally, called from Mailgun::Base
4
+ def initialize(mailgun)
5
+ @mailgun = mailgun
6
+ end
7
+
8
+ # List all bounces for a given domain
9
+ # * domain the domain for which all bounces will listed
10
+ def list(domain = Mailgun.domain)
11
+ response = Mailgun.submit :get, bounce_url(domain)
12
+
13
+ if response
14
+ response["items"].collect {|item| item["address"]}
15
+ end
16
+ end
17
+
18
+ def find(domain = Mailgun.domain, email)
19
+ Mailgun.submit :get, bounce_url(domain, email)
20
+ end
21
+
22
+ def add(domain = Mailgun.domain, email)
23
+ Mailgun.submit :post, bounce_url(domain), :address => email
24
+ end
25
+
26
+ private
27
+
28
+ # Helper method to generate the proper url for Mailgun mailbox API calls
29
+ def bounce_url(domain, address=nil)
30
+ domain = Mailgun.domain if Mailgun.domain
31
+ "#{@mailgun.base_url}/#{domain}/bounces#{'/' + address if address}"
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ module Mailgun
2
+ class Complaint
3
+ # Used internally, called from Mailgun::Base
4
+ def initialize(mailgun)
5
+ @mailgun = mailgun
6
+ end
7
+
8
+ # List all complaints for a given domain
9
+ # * domain the domain for which all complaints will listed
10
+ def list(domain = Mailgun.domain)
11
+ response = Mailgun.submit :get, complaint_url(domain)
12
+
13
+ if response
14
+ response["items"].collect {|item| item["address"]}
15
+ end
16
+ end
17
+
18
+ def find(domain = Mailgun.domain, email)
19
+ Mailgun.submit :get, complaint_url(domain, email)
20
+ end
21
+
22
+ def add(domain=Mailgun.domain, email)
23
+ Mailgun.submit :post, complaint_url(domain), {:address => email}
24
+ end
25
+
26
+ def remove(domain = Mailgun.domain, email)
27
+ Mailgun.submit :delete, complaint_url(domain, email)
28
+ end
29
+
30
+ private
31
+
32
+ # Helper method to generate the proper url for Mailgun complaints API calls
33
+ def complaint_url(domain, address=nil)
34
+ "#{@mailgun.base_url}/#{domain}/complaints#{'/' + address if address}"
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ module Mailgun
2
+ class List::Member
3
+ # Used internally, called from Mailgun::Base
4
+ def initialize(mailgun)
5
+ @mailgun = mailgun
6
+ end
7
+
8
+ ## List Member functionality
9
+
10
+ # List all mailing list members
11
+ # TODO add parameters: subscribed, limit, skip
12
+ def list(address)
13
+ response = Mailgun.submit :get, list_member_url(address)
14
+
15
+ if response
16
+ response["items"].collect {|item| item["address"]}
17
+ end
18
+ end
19
+
20
+ # List a single mailing list member by a given address
21
+ def find(address, member_address)
22
+ Mailgun.submit :get, list_member_url(address, member_address)
23
+ end
24
+
25
+ # Adds a mailing list member with a given address
26
+ # TODO add name, vars, subscribed, upsert
27
+ def add(address, member_address, name=nil, vars={}, subscribed='yes', upsert='no')
28
+ params = {:address => member_address, :subscribed => subscribed, :upsert => 'no'}
29
+ params[:name] = name if name
30
+ params[:vars] = vars unless vars.empty?
31
+ Mailgun.submit :post, list_member_url(address), params
32
+ end
33
+
34
+ # Update a mailing list member with a given address
35
+ # with an optional new member_address, name, vars and subscribed
36
+ def update(address, member_address, name=nil, vars={}, subscribed='yes')
37
+ params = {:address => member_address, :subscribed => subscribed}
38
+ params[:name] = name if name
39
+ params[:vars] = vars unless vars.empty?
40
+ Mailgun.submit :put, list_member_url(address, member_address), params
41
+ end
42
+
43
+ # Deletes a mailing list member with a given address
44
+ def remove(address, member_address)
45
+ Mailgun.submit :delete, list_member_url(address, member_address)
46
+ end
47
+
48
+
49
+ private
50
+
51
+ # Helper method to generate the proper url for Mailgun mailbox API calls
52
+ def list_member_url(address, member_address=nil)
53
+ "#{@mailgun.base_url}/lists#{'/' + address}/members#{'/' + member_address if member_address}"
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,59 @@
1
+ module Mailgun
2
+ class List
3
+ # Used internally, called from Mailgun::Base
4
+ def initialize(mailgun)
5
+ @mailgun = mailgun
6
+ end
7
+
8
+
9
+ ## List functionality
10
+
11
+ # TODO add default domain functionality for the address names of lists
12
+
13
+ # List all mailing lists
14
+ def all
15
+ response = Mailgun.submit :get, list_url
16
+
17
+ if response
18
+ response["items"].collect {|item| item["address"]}
19
+ end
20
+ end
21
+
22
+ # List a single mailing list by a given address
23
+ def find(address)
24
+ Mailgun.submit :get, list_url(address)
25
+ end
26
+
27
+ # Create a mailing list with a given address
28
+ # with an optional name and description
29
+ def create(address, name=nil, description=nil)
30
+ params = {:address => address}
31
+ params[:name] = name if name
32
+ params[:description] = description if description
33
+ Mailgun.submit :post, list_url, params
34
+ end
35
+
36
+ # Update a mailing list with a given address
37
+ # with an optional new address, name or description
38
+ def update(address, new_address, name=nil, description=nil)
39
+ params = {:address => new_address}
40
+ params[:name] = name if name
41
+ params[:description] = description if description
42
+ Mailgun.submit :put, list_url(address), params
43
+ end
44
+
45
+ # Deletes a mailing list with a given address
46
+ def delete(address)
47
+ Mailgun.submit :delete, list_url(address)
48
+ end
49
+
50
+
51
+ private
52
+
53
+ # Helper method to generate the proper url for Mailgun mailbox API calls
54
+ def list_url(address=nil)
55
+ "#{@mailgun.base_url}/lists#{'/' + address if address}"
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,26 @@
1
+ module Mailgun
2
+ class Log
3
+ # Used internally, called from Mailgun::Base
4
+ def initialize(mailgun)
5
+ @mailgun = mailgun
6
+ end
7
+
8
+ # List all logs for a given domain
9
+ # * domain the domain for which all complaints will listed
10
+ def list(domain=Mailgun.domain, limit=100, skip=0)
11
+ response = Mailgun.submit :get, log_url(domain), {:limit => limit, :skip => skip}
12
+
13
+ if response
14
+ response["items"].collect {|item| item["message"]}
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ # Helper method to generate the proper url for Mailgun complaints API calls
21
+ def log_url(domain)
22
+ "#{@mailgun.base_url}/#{domain}/log"
23
+ end
24
+
25
+ end
26
+ end
@@ -5,17 +5,21 @@ module Mailgun
5
5
  def initialize(mailgun)
6
6
  @mailgun = mailgun
7
7
  end
8
-
8
+
9
9
  # List all mailboxes for a given domain
10
10
  # * domain the domain for which all mailboxes will listed
11
- def list(domain)
12
- submit :get, mailbox_url(domain)
11
+ def list(domain = Mailgun.domain)
12
+ response = Mailgun.submit :get, mailbox_url(domain)
13
+
14
+ if response
15
+ response["items"].collect {|item| item["mailbox"]}
16
+ end
13
17
  end
14
18
 
15
19
 
16
20
  # Creates a mailbox on the Mailgun server with the given password
17
21
  def create(address, password)
18
- submit :post, mailbox_url(address.split("@").last), :mailbox => address,
22
+ Mailgun.submit :post, mailbox_url(address.split("@").last), :mailbox => address,
19
23
  :password => password
20
24
  end
21
25
 
@@ -24,7 +28,7 @@ module Mailgun
24
28
  def update_password(address, password)
25
29
  mailbox_name, domain = address.split("@")
26
30
 
27
- submit :put, mailbox_url(domain, mailbox_name), :password => password
31
+ Mailgun.submit :put, mailbox_url(domain, mailbox_name), :password => password
28
32
  end
29
33
 
30
34
 
@@ -32,7 +36,7 @@ module Mailgun
32
36
  def destroy(address)
33
37
  mailbox_name, domain = address.split("@")
34
38
 
35
- submit :delete, mailbox_url(domain, mailbox_name)
39
+ Mailgun.submit :delete, mailbox_url(domain, mailbox_name)
36
40
  end
37
41
 
38
42
 
@@ -43,10 +47,5 @@ module Mailgun
43
47
  "#{@mailgun.base_url}/#{domain}/mailboxes#{'/' + mailbox_name if mailbox_name}"
44
48
  end
45
49
 
46
-
47
- # Submits the API call to the Mailgun server
48
- def submit(method, url, parameters={})
49
- JSON(RestClient.send(method, url, parameters))
50
- end
51
50
  end
52
51
  end
@@ -0,0 +1,4 @@
1
+ module Mailgun
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,94 @@
1
+ module Mailgun
2
+ class Route
3
+
4
+ def initialize(mailgun)
5
+ @mailgun = mailgun
6
+ end
7
+
8
+ def list(limit=100, skip=0)
9
+ Mailgun.submit(:get, route_url, :limit => limit, :skip => skip)["items"] || []
10
+ end
11
+
12
+ def find(route_id)
13
+ Mailgun.submit(:get, route_url(route_id))["route"]
14
+ end
15
+
16
+ def create(description, priority, filter, actions)
17
+ data = ::Multimap.new
18
+
19
+ data['priority'] = priority
20
+ data['description'] = description
21
+ data['expression'] = build_filter(filter)
22
+
23
+ actions = build_actions(actions)
24
+
25
+ actions.each do |action|
26
+ data['action'] = action
27
+ end
28
+
29
+ # TODO: Raise an error or return false if unable to create route
30
+ Mailgun.submit(:post, route_url, data)["route"]["id"]
31
+ end
32
+
33
+ def update(route_id, params)
34
+ data = ::Multimap.new
35
+
36
+ ['priority', 'description'].each do |key|
37
+ data[key] = params[key] if params.has_key?(key)
38
+ end
39
+
40
+ data['expression'] = build_filter(params['expression']) if params.has_key?('expression')
41
+
42
+ if params.has_key?('actions')
43
+ actions = build_actions(params['actions'])
44
+
45
+ actions.each do |action|
46
+ data['action'] = action
47
+ end
48
+ end
49
+
50
+ Mailgun.submit(:put, route_url(route_id), data)
51
+ end
52
+
53
+ def destroy(route_id)
54
+ Mailgun.submit(:delete, route_url(route_id))["id"]
55
+ end
56
+
57
+ private
58
+
59
+ def route_url(route_id=nil)
60
+ "#{@mailgun.base_url}/routes#{'/' + route_id if route_id}"
61
+ end
62
+
63
+ def build_actions(actions)
64
+ _actions = []
65
+
66
+ actions.each do |action|
67
+ case action.first.to_sym
68
+ when :forward
69
+ _actions << "forward(\"#{action.last}\")"
70
+ when :stop
71
+ _actions << "stop()"
72
+ else
73
+ raise Mailgun::Error.new("Unsupported action requested, see http://documentation.mailgun.net/user_manual.html#routes for a list of allowed actions")
74
+ end
75
+ end
76
+
77
+ _actions
78
+ end
79
+
80
+
81
+ def build_filter(filter)
82
+ case filter.first.to_sym
83
+ when :match_recipient
84
+ return "match_recipient('#{filter.last}')"
85
+ when :match_header
86
+ return "match_header('#{filter[1]}', '#{filter.last}')"
87
+ when :catch_all
88
+ return "catch_all()"
89
+ else
90
+ raise Mailgun::Error.new("Unsupported filter requested, see http://documentation.mailgun.net/user_manual.html#routes for a list of allowed filters")
91
+ end
92
+ end
93
+ end
94
+ end