diff --git a/.gitignore b/.gitignore
index 9106b2a..fcd378d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,19 @@
 /.bundle/
 /.yardoc
+/Gemfile.lock
 /_yardoc/
 /coverage/
 /doc/
 /pkg/
 /spec/reports/
 /tmp/
+/.ruby-version
+/.ruby-gemset
+/.rvm
+*.bundle
+*.so
+*.o
+*.a
+mkmf.log
+scratch.rb
+*.sw[op]
\ No newline at end of file
diff --git a/.idea/autodiscover.iml b/.idea/autodiscover.iml
deleted file mode 100644
index bebf6e4..0000000
--- a/.idea/autodiscover.iml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="RUBY_MODULE" version="4">
-  <component name="ModuleRunConfigurationManager">
-    <shared />
-  </component>
-  <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
-    </content>
-    <orderEntry type="jdk" jdkName="ruby-3.2.3-p157" jdkType="RUBY_SDK" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index df535ce..8436560 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,10 +1,4 @@
-# frozen_string_literal: true
-
-source "https://rubygems.org"
+source 'https://rubygems.org'
 
 # Specify your gem's dependencies in autodiscover.gemspec
-gemspec
-
-gem "rake", "~> 13.0"
-
-gem "minitest", "~> 5.16"
+gemspec
\ No newline at end of file
diff --git a/Rakefile b/Rakefile
index a596216..43ef856 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,8 +1,19 @@
-# frozen_string_literal: true
-
 require "bundler/gem_tasks"
-require "minitest/test_task"
+require "rake/testtask"
 
-Minitest::TestTask.create
+task :default => :test
 
-task default: :test
+Rake::TestTask.new(:test) do |t|
+  t.libs << 'lib'
+  t.libs << 'test'
+  t.pattern = 'test/**/*_test.rb'
+  t.verbose = false
+end
+
+desc "Open a Pry console for this library"
+task :console do
+  require "pry"
+  require "autodiscover"
+  ARGV.clear
+  Pry.start
+end
\ No newline at end of file
diff --git a/autodiscover.gemspec b/autodiscover.gemspec
index d04c9ad..5363586 100644
--- a/autodiscover.gemspec
+++ b/autodiscover.gemspec
@@ -1,40 +1,32 @@
-# frozen_string_literal: true
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'autodiscover/version'
 
-require_relative "lib/autodiscover/version"
+Gem::Specification.new do |s|
+  s.name          = 'autodiscover'
+  s.version       = Autodiscover::VERSION
+  s.license       = 'MIT'
+  s.summary       = "Ruby client for Microsoft's Autodiscover Service"
+  s.description   = "The Autodiscover Service provides information about a Microsoft Exchange environment such as service URLs, versions and many other attributes."
+  s.required_ruby_version = '>= 2.1.0'
 
-Gem::Specification.new do |spec|
-  spec.name = "autodiscover"
-  spec.version = Autodiscover::VERSION
-  spec.authors = ["Toastie"]
-  spec.email = ["toastie@toastiet0ast.com"]
+  s.authors       = ["David King", "Dan Wanek"]
+  s.email         = ["dking@bestinclass.com", "dan.wanek@gmail.com"]
+  s.homepage      = 'http://github.com/WinRb/autodiscover'
 
-  spec.summary = "TODO: Write a short summary, because RubyGems requires one."
-  spec.description = "TODO: Write a longer description or delete this line."
-  spec.homepage = "TODO: Put your gem's website or public repo URL here."
-  spec.license = "MIT"
-  spec.required_ruby_version = ">= 3.0.0"
+  s.files         = `git ls-files -z`.split("\x0")
+  s.test_files    = s.files.grep(%r{^(test|spec|features)/})
+  s.require_paths = ["lib"]
 
-  spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
+  s.add_runtime_dependency  "nokogiri"
+  s.add_runtime_dependency  "nori"
+  s.add_runtime_dependency  "httpclient"
+  s.add_runtime_dependency  "logging"
 
-  spec.metadata["homepage_uri"] = spec.homepage
-  spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
-  spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
-
-  # Specify which files should be added to the gem when it is released.
-  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
-  spec.files = Dir.chdir(__dir__) do
-    `git ls-files -z`.split("\x0").reject do |f|
-      (File.expand_path(f) == __FILE__) ||
-        f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
-    end
-  end
-  spec.bindir = "exe"
-  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
-  spec.require_paths = ["lib"]
-
-  # Uncomment to register a new dependency of your gem
-  # spec.add_dependency "example-gem", "~> 1.0"
-
-  # For more information and examples about making a new gem, check out our
-  # guide at: https://bundler.io/guides/creating_gem.html
-end
+  s.add_development_dependency "minitest", "~> 5.6.0"
+  s.add_development_dependency "mocha", "~> 1.1.0"
+  s.add_development_dependency "bundler"
+  s.add_development_dependency "rake"
+  s.add_development_dependency "pry"
+end
\ No newline at end of file
diff --git a/lib/autodiscover.rb b/lib/autodiscover.rb
index 717b45b..6240dca 100644
--- a/lib/autodiscover.rb
+++ b/lib/autodiscover.rb
@@ -1,8 +1,23 @@
-# frozen_string_literal: true
-
-require_relative "autodiscover/version"
+require "autodiscover/version"
+require "nokogiri"
+require "nori"
+require "httpclient"
+require "logging"
 
 module Autodiscover
-  class Error < StandardError; end
-  # Your code goes here...
+  Logging.logger["Autodiscover"].level = :info
+
+  def self.Logger
+    Logging.logger["Autodiscover"]
+  end
+
+  def logger
+    @logger ||= Logging.logger[self.class.name]
+  end
 end
+
+require "autodiscover/errors"
+require "autodiscover/client"
+require "autodiscover/pox_request"
+require "autodiscover/pox_response"
+require "autodiscover/server_version_parser"
diff --git a/lib/autodiscover/client.rb b/lib/autodiscover/client.rb
index fc32d65..943c7f6 100644
--- a/lib/autodiscover/client.rb
+++ b/lib/autodiscover/client.rb
@@ -1,4 +1,34 @@
-# frozen_string_literal: true
+module Autodiscover
+  class Client
+    DEFAULT_HTTP_TIMEOUT = 10
+    attr_accessor :domain, :email, :http
 
-class Client
-end
+    # @param email [String] An e-mail to use for autodiscovery. It will be
+    #   used as the default username.
+    # @param password [String]
+    # @param username [String] An optional username if you want to authenticate
+    #   with something other than the e-mail. For instance DOMAIN\user
+    # @param domain [String] An optional domain to provide as an override for
+    #   the one parsed from the e-mail.
+    def initialize(email:, password:, username: nil, domain: nil, connect_timeout: DEFAULT_HTTP_TIMEOUT)
+      @email = email
+      @domain = domain || @email.split('@').last
+      @http = HTTPClient.new
+      @http.connect_timeout = connect_timeout if connect_timeout
+      @username = username || @email
+      @http.set_auth(nil, @username, password)
+    end
+
+    # @param type [Symbol] The type of response. Right now this is just :pox
+    # @param [Hash] **options
+    def autodiscover(type: :pox, **options)
+      case type
+      when :pox
+        PoxRequest.new(self, **options).autodiscover
+      else
+        raise Autodiscover::ArgumentError, "Not a valid autodiscover type (#{type})."
+      end
+    end
+
+  end
+end
\ No newline at end of file
diff --git a/lib/autodiscover/debug.rb b/lib/autodiscover/debug.rb
index 07e8df1..d5c8b3d 100644
--- a/lib/autodiscover/debug.rb
+++ b/lib/autodiscover/debug.rb
@@ -1,2 +1,4 @@
-# frozen_string_literal: true
-
+module Autodiscover
+  Logging.logger["Autodiscover"].level = :debug
+  Logging.logger["Autodiscover"].appenders = Logging.appenders.stdout
+end
\ No newline at end of file
diff --git a/lib/autodiscover/errors.rb b/lib/autodiscover/errors.rb
index e69de29..eb49a30 100644
--- a/lib/autodiscover/errors.rb
+++ b/lib/autodiscover/errors.rb
@@ -0,0 +1,5 @@
+module Autodiscover
+  class Error < ::StandardError; end
+
+  class ArgumentError < Error; end
+end
\ No newline at end of file
diff --git a/lib/autodiscover/pox_request.rb b/lib/autodiscover/pox_request.rb
index 213fc98..251abc5 100644
--- a/lib/autodiscover/pox_request.rb
+++ b/lib/autodiscover/pox_request.rb
@@ -1,4 +1,77 @@
-# frozen_string_literal: true
+module Autodiscover
+  class PoxRequest
+    include Autodiscover
 
-module PoxRequest
-end
+    attr_reader :client, :options
+
+    # @param client [Autodiscover::Client]
+    # @param [Hash] **options
+    # @option **options [Boolean] :ignore_ssl_errors Whether to keep trying if
+    #   there are SSL errors
+    def initialize(client, **options)
+      @client = client
+      @options = options
+    end
+
+    # @return [Autodiscover::PoxResponse, nil]
+    def autodiscover
+      available_urls.each do |url|
+        response = client.http.post(url, request_body, {'Content-Type' => 'text/xml; charset=utf-8'})
+        return PoxResponse.new(response.body) if good_response?(response)
+      end
+    end
+
+    private
+
+    def good_response?(response)
+      response.status == 200
+    end
+
+    def available_urls(&block)
+      return to_enum(__method__) unless block_given?
+      formatted_https_urls.each {|url|
+        logger.debug "Yielding HTTPS Url #{url}"
+        handle_allowed_errors do
+          yield url
+        end
+      }
+      handle_allowed_errors do
+        logger.debug "Yielding HTTP Redirected Url #{redirected_http_url}"
+        yield redirected_http_url
+      end
+    end
+
+    def formatted_https_urls
+      @formatted_urls ||= %W{
+        https://#{client.domain}/autodiscover/autodiscover.xml
+        https://autodiscover.#{client.domain}/autodiscover/autodiscover.xml
+      }
+    end
+
+    def redirected_http_url
+      @redirected_http_url ||=
+        begin
+          response = client.http.get("http://autodiscover.#{client.domain}/autodiscover/autodiscover.xml")
+          (response.status == 302) ? response.headers["Location"] : nil
+        end
+    end
+
+    def request_body
+      Nokogiri::XML::Builder.new do |xml|
+        xml.Autodiscover('xmlns' => 'http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006') {
+          xml.Request {
+            xml.EMailAddress client.email
+            xml.AcceptableResponseSchema 'http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a'
+          }
+        }
+      end.to_xml
+    end
+
+    def handle_allowed_errors
+      yield
+    rescue SocketError, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ECONNREFUSED, HTTPClient::ConnectTimeoutError
+    rescue OpenSSL::SSL::SSLError
+      raise if !options[:ignore_ssl_errors]
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/autodiscover/pox_response.rb b/lib/autodiscover/pox_response.rb
index 98a5a91..269621b 100644
--- a/lib/autodiscover/pox_response.rb
+++ b/lib/autodiscover/pox_response.rb
@@ -1,4 +1,32 @@
-# frozen_string_literal: true
+module Autodiscover
+  class PoxResponse
 
-class PoxResponse
-end
+    attr_reader :response
+
+    def initialize(response)
+      raise ArgumentError, "Response must be an XML string" if(response.nil? || response.empty?)
+      @response = Nori.new(parser: :nokogiri).parse(response)["Autodiscover"]["Response"]
+    end
+
+    def exchange_version
+      ServerVersionParser.new(exch_proto["ServerVersion"]).exchange_version
+    end
+
+    def ews_url
+      expr_proto["EwsUrl"]
+    end
+
+    def exch_proto
+      @exch_proto ||= (response["Account"]["Protocol"].select{|p| p["Type"] == "EXCH"}.first || {})
+    end
+
+    def expr_proto
+      @expr_proto ||= (response["Account"]["Protocol"].select{|p| p["Type"] == "EXPR"}.first || {})
+    end
+
+    def web_proto
+      @web_proto ||= (response["Account"]["Protocol"].select{|p| p["Type"] == "WEB"}.first || {})
+    end
+
+  end
+end
\ No newline at end of file
diff --git a/lib/autodiscover/server_version_parser.rb b/lib/autodiscover/server_version_parser.rb
index b70c619..1de6fbc 100644
--- a/lib/autodiscover/server_version_parser.rb
+++ b/lib/autodiscover/server_version_parser.rb
@@ -1,4 +1,45 @@
-# frozen_string_literal: true
+module Autodiscover
+  class ServerVersionParser
 
-class ServerVersionParser
-end
+    VERSIONS = {
+      8 => {
+        0 => "Exchange2007",
+        1 => "Exchange2007_SP1",
+        2 => "Exchange2007_SP1",
+        3 => "Exchange2007_SP1",
+      },
+      14 => {
+        0 => "Exchange2010",
+        1 => "Exchange2010_SP1",
+        2 => "Exchange2010_SP2",
+        3 => "Exchange2010_SP2",
+      },
+      15 => {
+        0 => "Exchange2013",
+        1 => "Exchange2013_SP1",
+      }
+    }
+
+    def initialize(hexversion)
+      @version = hexversion.hex.to_s(2).rjust(hexversion.size*4, '0')
+    end
+
+    def major
+      @version[4..9].to_i(2)
+    end
+
+    def minor
+      @version[10..15].to_i(2)
+    end
+
+    def build
+      @version[17..31].to_i(2)
+    end
+
+    def exchange_version
+      v = VERSIONS[major][minor]
+      v.nil? ? VERIONS[8][0] : v
+    end
+
+  end
+end
\ No newline at end of file
diff --git a/lib/autodiscover/version.rb b/lib/autodiscover/version.rb
index 8968370..f7880f7 100644
--- a/lib/autodiscover/version.rb
+++ b/lib/autodiscover/version.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
 module Autodiscover
-  VERSION = "0.1.0"
+  VERSION = "1.0.2"
 end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 32c0671..71751f0 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,6 +1,12 @@
-# frozen_string_literal: true
-
-$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
-require "autodiscover"
-
+require File.expand_path('../../lib/autodiscover.rb', __FILE__)
+require 'minitest/autorun'
 require "minitest/autorun"
+require "mocha/mini_test"
+
+TEST_DIR = File.dirname(__FILE__)
+
+class MiniTest::Spec
+  def load_sample(name)
+    File.read("#{TEST_DIR}/fixtures/#{name}")
+  end
+end
\ No newline at end of file
diff --git a/test/units/client_test.rb b/test/units/client_test.rb
index 48836ea..c9835ca 100644
--- a/test/units/client_test.rb
+++ b/test/units/client_test.rb
@@ -1,17 +1,35 @@
-# frozen_string_literal: true
+require "test_helper"
 
-require 'minitest/autorun'
+describe Autodiscover::Client do
+  let(:_class) { Autodiscover::Client }
 
-class ClientTest < Minitest::Test
-  def setup
-    # Do nothing
+  describe "#initialize" do
+    it "sets a username and domain from the email" do
+      inst = _class.new(email: "test@example.local", password: "test")
+      _(inst.domain).must_equal "example.local"
+      _(inst.instance_variable_get(:@username)).must_equal "test@example.local"
+    end
+
+    it "allows you to override the username and domain" do
+      inst = _class.new(email: "test@example.local", password: "test", username: 'DOMAIN\test', domain: "otherexample.local")
+      _(inst.domain).must_equal "otherexample.local"
+      _(inst.instance_variable_get(:@username)).must_equal 'DOMAIN\test'
+    end
   end
 
-  def teardown
-    # Do nothing
+  describe "#autodiscover" do
+    it "dispatches autodiscover to a PoxRequest instance" do
+      inst = _class.new(email: "test@example.local", password: "test")
+      pox_request = mock("pox")
+      pox_request.expects(:autodiscover)
+      Autodiscover::PoxRequest.expects(:new).with(inst,{}).returns(pox_request)
+      inst.autodiscover
+    end
+
+    it "raises an exception if an invalid autodiscover type is passed" do
+      inst = _class.new(email: "test@example.local", password: "test")
+      ->{ inst.autodiscover(type: :invalid) }.must_raise(Autodiscover::ArgumentError)
+    end
   end
 
-  def test
-    skip 'Not implemented'
-  end
-end
+end
\ No newline at end of file
diff --git a/test/units/pox_request_test.rb b/test/units/pox_request_test.rb
index 6ccae63..d615deb 100644
--- a/test/units/pox_request_test.rb
+++ b/test/units/pox_request_test.rb
@@ -1,4 +1,46 @@
-# frozen_string_literal: true
+require "test_helper"
+require "ostruct"
 
-class PoxRequestTest
-end
+describe Autodiscover::PoxRequest do
+  let(:_class) {Autodiscover::PoxRequest }
+  let(:http) { mock("http") }
+  let(:client) { OpenStruct.new({http: http, domain: "example.local", email: "test@example.local"}) }
+
+  describe "#autodiscover" do
+    it "returns a PoxResponse if the autodiscover is successful" do
+      request_body = <<-EOF.gsub(/^        /,"")
+        <?xml version="1.0"?>
+        <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
+          <Request>
+            <EMailAddress>test@example.local</EMailAddress>
+            <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
+          </Request>
+        </Autodiscover>
+      EOF
+      http.expects(:post).with(
+        "https://example.local/autodiscover/autodiscover.xml", request_body,
+        {'Content-Type' => 'text/xml; charset=utf-8'}
+      ).returns(OpenStruct.new({status: 200, body: "<Autodiscover><Response><test></test></Response></Autodiscover>"}))
+
+      inst = _class.new(client)
+      _(inst.autodiscover).must_be_instance_of(Autodiscover::PoxResponse)
+    end
+
+    it "will fail if :ignore_ssl_errors is not true" do
+      http.expects(:post).raises(OpenSSL::SSL::SSLError, "Test Error")
+      inst = _class.new(client)
+      -> {inst.autodiscover}.must_raise(OpenSSL::SSL::SSLError)
+    end
+
+    it "keeps trying if :ignore_ssl_errors is set" do
+      http.expects(:get).once.returns(OpenStruct.new({headers: {"Location" => "http://example.local"}, status: 302}))
+      http.expects(:post).times(3).
+        raises(OpenSSL::SSL::SSLError, "Test Error").then.
+        raises(OpenSSL::SSL::SSLError, "Test Error").then.
+        raises(Errno::ENETUNREACH, "Test Error")
+      inst = _class.new(client, ignore_ssl_errors: true)
+      _(inst.autodiscover).must_be_nil
+    end
+
+  end
+end
\ No newline at end of file
diff --git a/test/units/pox_response_test.rb b/test/units/pox_response_test.rb
index bde15c9..2bddc7c 100644
--- a/test/units/pox_response_test.rb
+++ b/test/units/pox_response_test.rb
@@ -1,17 +1,54 @@
-# frozen_string_literal: true
+require "test_helper"
 
-require 'minitest/autorun'
+describe Autodiscover::PoxResponse do
+  let(:_class) {Autodiscover::PoxResponse }
+  let(:response) { load_sample("pox_response.xml") }
 
-class PoxResponseTest < Minitest::Test
-  def setup
-    # Do nothing
+  describe "#initialize" do
+    it "parses an XML string into a Hash when initialized" do
+      inst = _class.new response
+      _(inst.response).must_be_instance_of Hash
+    end
+
+    it "it raises an exception if the response is empty or nil" do
+      ->{_class.new ""}.must_raise(Autodiscover::ArgumentError)
+      ->{_class.new nil}.must_raise(Autodiscover::ArgumentError)
+    end
   end
 
-  def teardown
-    # Do nothing
+  describe "#exchange_version" do
+    it "returns an Exchange version usable for EWS" do
+      _(_class.new(response).exchange_version).must_equal "Exchange2013_SP1"
+    end
   end
 
-  def test
-    skip 'Not implemented'
+  describe "#ews_url" do
+    it "returns the EWS url" do
+      _(_class.new(response).ews_url).must_equal "https://outlook.office365.com/EWS/Exchange.asmx"
+    end
   end
-end
+
+  describe "Protocol Hashes" do
+    let(:_inst) { _class.new(response) }
+
+    it "returns the EXCH protocol Hash" do
+      _(_inst.exch_proto["Type"]).must_equal "EXCH"
+    end
+
+    it "returns the EXPR protocol Hash" do
+      _(_inst.expr_proto["Type"]).must_equal "EXPR"
+    end
+
+    it "returns the WEB protocol Hash" do
+      _(_inst.web_proto["Type"]).must_equal "WEB"
+    end
+
+    it "returns empty Hashes when the protocols are missing" do
+      _inst.response["Account"]["Protocol"] = []
+      _(_inst.exch_proto).must_equal({})
+      _(_inst.expr_proto).must_equal({})
+      _(_inst.web_proto).must_equal({})
+    end
+  end
+
+end
\ No newline at end of file
diff --git a/test/units/server_version_parser_test.rb b/test/units/server_version_parser_test.rb
index 1d50ecf..62a17e9 100644
--- a/test/units/server_version_parser_test.rb
+++ b/test/units/server_version_parser_test.rb
@@ -1,17 +1,18 @@
-# frozen_string_literal: true
+require "test_helper"
 
-require 'minitest/autorun'
+describe Autodiscover::ServerVersionParser do
+  let(:_class) { Autodiscover::ServerVersionParser }
 
-class ServerVersionParserTest < Minitest::Test
-  def setup
-    # Do nothing
+  it "parses a hex ServerVersion response" do
+    inst = _class.new("738180DA")
+    _(inst.major).must_equal 14
+    _(inst.minor).must_equal 1
+    _(inst.build).must_equal 218
   end
 
-  def teardown
-    # Do nothing
+  it "returns an Exchange Server Version" do
+    inst = _class.new("738180DA")
+    inst.exchange_version.must_equal "Exchange2010_SP1"
   end
 
-  def test
-    skip 'Not implemented'
-  end
-end
+end
\ No newline at end of file