Repository: Stranger6667/postmarker

Issue:
Configurable resend on fail

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=h1) Report
> Merging [#138](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=desc) into [master](https://codecov.io/gh/Stranger6667/postmarker/commit/62cc043528a344477ee4b8117e08865c52aa50fe?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/Stranger6667/postmarker/pull/138/graphs/tree.svg?width=650&height=150&src=pr&token=ntmpbnZMPl)](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master   #138   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          20     20           
  Lines         790    795    +5     
  Branches       63     63           
=====================================
+ Hits          790    795    +5
```


| [Impacted Files](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [postmarker/core.py](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=tree#diff-cG9zdG1hcmtlci9jb3JlLnB5) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=footer). Last update [62cc043...574f2de](https://codecov.io/gh/Stranger6667/postmarker/pull/138?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 067a7e1..fd2198f 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -10,6 +10,7 @@ Added
 ~~~~~
 
 - ``message`` property for ``Bounce``, ``Delivery`` and ``Open`` classes to access corresponding ``OutboundMessage`` instance. `#119`_
+- An ability to control timeout and retries behaviour. `#82`_
 
 `0.10.1`_ - 2017-04-03
 ----------------------
@@ -299,6 +300,7 @@ Fixed
 .. _#92: https://github.com/Stranger6667/postmarker/issues/92
 .. _#87: https://github.com/Stranger6667/postmarker/issues/87
 .. _#83: https://github.com/Stranger6667/postmarker/issues/83
+.. _#82: https://github.com/Stranger6667/postmarker/issues/82
 .. _#78: https://github.com/Stranger6667/postmarker/issues/78
 .. _#76: https://github.com/Stranger6667/postmarker/issues/76
 .. _#75: https://github.com/Stranger6667/postmarker/issues/75
diff --git a/docs/usage.rst b/docs/usage.rst
index 9c427b1..f901781 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -20,4 +20,8 @@ By default, logging is configured to be silent. To enable it, pass ``verbosity``
 
     >>> postmark = PostmarkClient(server_token='SERVER_TOKEN', account_token='ACCOUNT_TOKEN', verbosity=3)
 
-With ``verbosity=3`` every request and response will be logged to the console.
\ No newline at end of file
+With ``verbosity=3`` every request and response will be logged to the console.
+
+For timeouts and max_retries handling there are two parameters - ``max_retries`` and ``timeout``.
+The ``timeout`` value is passed to `requests.Session.request <http://docs.python-requests.org/en/master/api/#requests.Session.request>`_.
+``max_retries`` is passed to `requests.adapters.HTTPAdapter <http://docs.python-requests.org/en/master/api/#requests.adapters.HTTPAdapter>`_.
diff --git a/postmarker/core.py b/postmarker/core.py
index 6dbe3d4..5d56837 100644
--- a/postmarker/core.py
+++ b/postmarker/core.py
@@ -41,10 +41,12 @@ class PostmarkClient(object):
         TriggersManager,
     )
 
-    def __init__(self, server_token=None, account_token=None, verbosity=0):
+    def __init__(self, server_token=None, account_token=None, verbosity=0, max_retries=0, timeout=None):
         assert server_token, 'You have to provide token to use Postmark API'
         self.server_token = server_token
         self.account_token = account_token
+        self.max_retries = max_retries
+        self.timeout = timeout
         self.logger = get_logger('Postmarker', verbosity)
         self._setup_managers()
 
@@ -67,6 +69,9 @@ class PostmarkClient(object):
     def session(self):
         if not hasattr(self, '_session'):
             self._session = requests.Session()
+            adapter = requests.adapters.HTTPAdapter(max_retries=self.max_retries)
+            self._session.mount('http://', adapter)
+            self._session.mount('https://', adapter)
         return self._session
 
     def call(self, method, endpoint, token_type='server', data=None, **kwargs):
@@ -104,7 +109,9 @@ class PostmarkClient(object):
             default_headers.update(headers)
         url = urljoin(root, endpoint)
         self.logger.debug('Request: %s %s, Data: %s', method, url, data)
-        response = self.session.request(method, url, json=data, params=kwargs, headers=default_headers)
+        response = self.session.request(
+            method, url, json=data, params=kwargs, headers=default_headers, timeout=self.timeout
+        )
         self.logger.debug('Response: %s', response.text)
         self.check_response(response)
         return response.json()


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 9e90535..8a6fbba 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -14,7 +14,7 @@ class TestClient:
             'GET',
             'https://api.postmarkapp.com/endpoint',
             headers={'X-Postmark-Server-Token': server_token, 'Accept': 'application/json', 'User-Agent': USER_AGENT},
-            params={}, json=None,
+            params={}, json=None, timeout=None
         )
 
     def test_no_token(self):