Skip to content

Commit 762325e

Browse files
authored
Merge pull request #7 from emailable/add-access-token-authentication
Add Access Token Authentication Support
2 parents ce570d0 + 1d38d5f commit 762325e

File tree

5 files changed

+82
-41
lines changed

5 files changed

+82
-41
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
15+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
1616

1717
steps:
1818
- uses: actions/checkout@v4

README.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,26 @@ pip install emailable
1818

1919
## Usage
2020

21-
The library needs to be configured with your account's API key which is available in your [Emailable Dashboard](https://app.emailable.com/api).
21+
### Authentication
2222

23-
### Setup
23+
The Emailable API requires either an API key or an access token for
24+
authentication. API keys can be created and managed in the
25+
[Emailable Dashboard](https://app.emailable.com/api).
26+
27+
An API key can be set globally for the Emailable client:
28+
29+
```python
30+
client = emailable.Client('your_api_key')
31+
```
32+
33+
Or, you can specify an `api_key` or an `access_token` with each request:
2434

2535
```python
26-
import emailable
36+
# set api_key at request time
37+
client.verify(api_key='your_api_key')
2738

28-
client = emailable.Client('live_...')
39+
# set access_token at request time
40+
client.verify(access_token='your_access_token')
2941
```
3042

3143
### Verification
@@ -36,7 +48,7 @@ response = client.verify('evan@emailable.com')
3648
response.state
3749
=> 'deliverable'
3850

39-
# additional parameters are available. see API docs for additional info.
51+
# additional parameters are available. see API docs for more info.
4052
client.verify('evan@emailable.com', smtp=False, accept_all=True, timeout=25)
4153
```
4254

emailable/client.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66

77
class Client:
88

9-
def __init__(self, api_key):
9+
def __init__(self, api_key=None):
1010
self.api_key = api_key
1111
self.base_url = 'https://api.emailable.com/v1/'
1212

13-
def verify(self, email, smtp=True, accept_all=False, timeout=None):
13+
def verify(self,
14+
email,
15+
smtp=True,
16+
accept_all=False,
17+
timeout=None,
18+
api_key=None,
19+
access_token=None):
1420
options = {
1521
'params': {
16-
'api_key': self.api_key,
1722
'email': email,
1823
'smtp': str(smtp).lower(),
1924
'accept_all': str(accept_all).lower(),
@@ -22,45 +27,44 @@ def verify(self, email, smtp=True, accept_all=False, timeout=None):
2227
}
2328

2429
url = self.base_url + 'verify'
25-
return self.__request('get', url, options)
30+
return self.__request('get', url, options, api_key or access_token)
2631

27-
def batch(self, emails, params={}):
32+
def batch(self, emails, params={}, api_key=None, access_token=None):
2833
options = {
2934
'params': {
30-
**{'api_key': self.api_key},
3135
**params
3236
},
3337
'json': {
3438
'emails': emails
3539
}
3640
}
3741
url = self.base_url + 'batch'
38-
return self.__request('post', url, options)
42+
return self.__request('post', url, options, api_key or access_token)
3943

40-
def batch_status(self, batch_id, simulate=None):
44+
def batch_status(self,
45+
batch_id,
46+
simulate=None,
47+
api_key=None,
48+
access_token=None):
4149
options = {
4250
'params': {
43-
'api_key': self.api_key,
4451
'id': batch_id,
4552
'simulate': simulate
4653
}
4754
}
4855

4956
url = self.base_url + 'batch'
50-
return self.__request('get', url, options)
51-
52-
def account(self):
53-
options = {
54-
'params': {
55-
'api_key': self.api_key
56-
}
57-
}
57+
return self.__request('get', url, options, api_key or access_token)
5858

59+
def account(self, api_key=None, access_token=None):
5960
url = self.base_url + 'account'
60-
return self.__request('get', url, options)
61+
return self.__request('get', url, {}, api_key or access_token)
6162

62-
def __request(self, method, url, options):
63+
def __request(self, method, url, options, key_or_token):
6364
response = None
65+
options['headers'] = {
66+
'Authorization': f'Bearer {key_or_token or self.api_key}'
67+
}
6468
try:
6569
response = requests.request(method, url, **options)
6670
response.raise_for_status()

tests/test_authentication.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from unittest import TestCase
2+
import emailable
3+
4+
class TestAuthentication(TestCase):
5+
6+
def setUp(self):
7+
self.api_key = 'test_7aff7fc0142c65f86a00'
8+
self.email = 'evan@emailable.com'
9+
self.emails = ['evan@emailable.com', 'jarrett@emailable.com']
10+
11+
def test_invalid_api_key_authentication(self):
12+
client = emailable.Client('test_7aff7fc0141c65f86a00')
13+
self.assertRaises(
14+
emailable.AuthError,
15+
client.verify,
16+
'evan@emailable.com'
17+
)
18+
19+
def test_missing_api_key_authentication(self):
20+
client = emailable.Client()
21+
self.assertRaises(
22+
emailable.AuthError,
23+
client.verify,
24+
'evan@emailable.com'
25+
)
26+
27+
def test_global_api_key_authentication(self):
28+
client = emailable.Client(self.api_key)
29+
self.assertIsNotNone(client.verify(self.email).domain)
30+
batch_id = client.batch(self.emails).id
31+
self.assertIsNotNone(batch_id)
32+
self.assertIsNotNone(client.batch_status(batch_id).id)
33+
self.assertIsNotNone(client.account().available_credits)
34+
35+
def test_request_time_api_key_authentication(self):
36+
client = emailable.Client()
37+
self.assertIsNotNone(client.verify(self.email, api_key=self.api_key).domain)
38+
batch_id = client.batch(self.emails, api_key=self.api_key).id
39+
self.assertIsNotNone(batch_id)
40+
self.assertIsNotNone(client.batch_status(batch_id, api_key=self.api_key).id)
41+
self.assertIsNotNone(client.account(api_key=self.api_key).available_credits)

tests/test_client.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,6 @@ def setUp(self):
77
self.client = emailable.Client('test_7aff7fc0142c65f86a00')
88
time.sleep(0.5)
99

10-
def test_invalid_api_key(self):
11-
client = emailable.Client('test_7aff7fc0141c65f86a00')
12-
self.assertRaises(
13-
emailable.AuthError,
14-
client.verify,
15-
'evan@emailable.com'
16-
)
17-
18-
def test_missing_api_key(self):
19-
self.client.api_key = None
20-
self.assertRaises(
21-
emailable.AuthError,
22-
self.client.verify,
23-
'evan@emailable.com'
24-
)
25-
2610
def test_verify_returns_response(self):
2711
response = self.client.verify('johndoe+tag@emailable.com')
2812
self.assertIsInstance(response, emailable.Response)

0 commit comments

Comments
 (0)