forked from sendgrid/sendgrid-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsendgrid.py
More file actions
138 lines (120 loc) · 5.04 KB
/
sendgrid.py
File metadata and controls
138 lines (120 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import sys
import json
from socket import timeout
from .version import __version__
try:
import urllib.request as urllib_request
from urllib.parse import urlencode
from urllib.error import HTTPError
except ImportError: # Python 2
import urllib2 as urllib_request
from urllib2 import HTTPError
from urllib import urlencode
from .exceptions import SendGridClientError, SendGridServerError
class SendGridClient(object):
"""SendGrid API."""
def __init__(self, username_or_apikey, password=None, **opts):
"""
Construct SendGrid API object.
Args:
username: SendGrid username
password: SendGrid password
user: Send mail on behalf of this user (web only)
raise_errors: If set to False (default): in case of error, `.send`
method will return a tuple (http_code, error_message). If set
to True: `.send` will raise SendGridError. Note, from version
1.0.0, the default will be changed to True, so you are
recommended to pass True for forwards compatability.
"""
# Check if username + password or api key
if password is None:
# API Key
self.username = None
self.password = username_or_apikey
else:
# Username + password
self.username = username_or_apikey
self.password = password
self.useragent = 'sendgrid/' + __version__ + ';python'
self.host = opts.get('host', 'https://api.sendgrid.com')
self.port = str(opts.get('port', '443'))
self.endpoint = opts.get('endpoint', '/api/mail.send.json')
self.mail_url = self.host + ':' + self.port + self.endpoint
self._raise_errors = opts.get('raise_errors', False)
# urllib cannot connect to SSL servers using proxies
self.proxies = opts.get('proxies', None)
def _build_body(self, message):
if sys.version_info < (3, 0):
ks = ['from_email', 'from_name', 'subject',
'text', 'html', 'reply_to']
for k in ks:
v = getattr(message, k)
if isinstance(v, unicode):
setattr(message, k, v.encode('utf-8'))
values = {
'to[]': message.to if message.to else [message.from_email],
'toname[]': message.to_name,
'cc[]': message.cc,
'bcc[]': message.bcc,
'from': message.from_email,
'fromname': message.from_name,
'subject': message.subject,
'text': message.text,
'html': message.html,
'replyto': message.reply_to,
'headers': json.dumps(message.headers) if message.headers else '',
'date': message.date,
'x-smtpapi': message.json_string()
}
if self.username != None:
# Using username + password
values['api_user'] = self.username
values['api_key'] = self.password
for k in list(values.keys()):
if not values[k]:
del values[k]
for filename in message.files:
if message.files[filename]:
values['files[' + filename + ']'] = message.files[filename]
for content in message.content:
if message.content[content]:
values['content[' + content + ']'] = message.content[content]
return values
def _make_request(self, message):
if self.proxies:
proxy_support = urllib_request.ProxyHandler(self.proxies)
opener = urllib_request.build_opener(proxy_support)
urllib_request.install_opener(opener)
data = urlencode(self._build_body(message), True).encode('utf-8')
req = urllib_request.Request(self.mail_url, data)
req.add_header('User-Agent', self.useragent)
if self.username is None:
# Using API key
req.add_header('Authorization', 'Bearer ' + self.password)
response = urllib_request.urlopen(req, timeout=10)
body = response.read()
return response.getcode(), body
def send(self, message):
if self._raise_errors:
return self._raising_send(message)
else:
return self._legacy_send(message)
def _legacy_send(self, message):
try:
return self._make_request(message)
except HTTPError as e:
return e.code, e.read()
except timeout as e:
return 408, e
def _raising_send(self, message):
try:
return self._make_request(message)
except HTTPError as e:
if 400 <= e.code < 500:
raise SendGridClientError(e.code, e.read())
elif 500 <= e.code < 600:
raise SendGridServerError(e.code, e.read())
else:
assert False
except timeout as e:
raise SendGridClientError(408, 'Request timeout')