django-gmailapi-backend 0.3.3__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (18) hide show
  1. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/PKG-INFO +9 -1
  2. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/README.md +7 -0
  3. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/django_gmailapi_backend.egg-info/PKG-INFO +9 -1
  4. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/django_gmailapi_backend.egg-info/requires.txt +1 -0
  5. django_gmailapi_backend-0.3.4/gmailapi_backend/__init__.py +1 -0
  6. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/gmailapi_backend/bin/gmail_oauth2.py +165 -112
  7. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/gmailapi_backend/mail.py +31 -15
  8. django_gmailapi_backend-0.3.4/setup.py +51 -0
  9. django_gmailapi_backend-0.3.3/gmailapi_backend/__init__.py +0 -1
  10. django_gmailapi_backend-0.3.3/setup.py +0 -49
  11. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/LICENSE +0 -0
  12. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/django_gmailapi_backend.egg-info/SOURCES.txt +0 -0
  13. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/django_gmailapi_backend.egg-info/dependency_links.txt +0 -0
  14. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/django_gmailapi_backend.egg-info/entry_points.txt +0 -0
  15. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/django_gmailapi_backend.egg-info/top_level.txt +0 -0
  16. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/gmailapi_backend/bin/__init__.py +0 -0
  17. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/requirements.txt +0 -0
  18. {django_gmailapi_backend-0.3.3 → django_gmailapi_backend-0.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-gmailapi-backend
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: Email backend for Django which sends email via the Gmail API
5
5
  Home-page: https://github.com/dolfim/django-gmailapi-backend
6
6
  Author: Michele Dolfi
@@ -24,6 +24,7 @@ Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Requires-Dist: google-api-python-client~=2.0
26
26
  Requires-Dist: google-auth<3.0.0dev,>=1.16.0
27
+ Requires-Dist: google-auth-oauthlib>=1.4.0
27
28
  Dynamic: author
28
29
  Dynamic: author-email
29
30
  Dynamic: classifier
@@ -100,3 +101,10 @@ the setup of the API credentials. The following outlines the key steps:
100
101
  --scope="https://www.googleapis.com/auth/gmail.send"
101
102
  ```
102
103
 
104
+ > [!NOTE]
105
+ > OOB flow is deprecated so ```--generate_oauth2_token``` can fail. To overcome this issue try instead ```--ugo2t``` option with the following syntax
106
+ ```sh
107
+ gmail_oauth2 --ugo2t \
108
+ --credentials_path="<credentials_relative_path>" # need to be download from gcp after creating an Oauth2 client
109
+ ```
110
+
@@ -63,3 +63,10 @@ the setup of the API credentials. The following outlines the key steps:
63
63
  --scope="https://www.googleapis.com/auth/gmail.send"
64
64
  ```
65
65
 
66
+ > [!NOTE]
67
+ > OOB flow is deprecated so ```--generate_oauth2_token``` can fail. To overcome this issue try instead ```--ugo2t``` option with the following syntax
68
+ ```sh
69
+ gmail_oauth2 --ugo2t \
70
+ --credentials_path="<credentials_relative_path>" # need to be download from gcp after creating an Oauth2 client
71
+ ```
72
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-gmailapi-backend
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: Email backend for Django which sends email via the Gmail API
5
5
  Home-page: https://github.com/dolfim/django-gmailapi-backend
6
6
  Author: Michele Dolfi
@@ -24,6 +24,7 @@ Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
25
  Requires-Dist: google-api-python-client~=2.0
26
26
  Requires-Dist: google-auth<3.0.0dev,>=1.16.0
27
+ Requires-Dist: google-auth-oauthlib>=1.4.0
27
28
  Dynamic: author
28
29
  Dynamic: author-email
29
30
  Dynamic: classifier
@@ -100,3 +101,10 @@ the setup of the API credentials. The following outlines the key steps:
100
101
  --scope="https://www.googleapis.com/auth/gmail.send"
101
102
  ```
102
103
 
104
+ > [!NOTE]
105
+ > OOB flow is deprecated so ```--generate_oauth2_token``` can fail. To overcome this issue try instead ```--ugo2t``` option with the following syntax
106
+ ```sh
107
+ gmail_oauth2 --ugo2t \
108
+ --credentials_path="<credentials_relative_path>" # need to be download from gcp after creating an Oauth2 client
109
+ ```
110
+
@@ -1,2 +1,3 @@
1
1
  google-api-python-client~=2.0
2
2
  google-auth<3.0.0dev,>=1.16.0
3
+ google-auth-oauthlib>=1.4.0
@@ -0,0 +1 @@
1
+ __version__ = "0.3.4"
@@ -6,7 +6,7 @@
6
6
  # you may not use this file except in compliance with the License.
7
7
  # You may obtain a copy of the License at
8
8
  #
9
- # http://www.apache.org/licenses/LICENSE-2.0
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
10
  #
11
11
  # Unless required by applicable law or agreed to in writing, software
12
12
  # distributed under the License is distributed on an "AS IS" BASIS,
@@ -65,10 +65,9 @@ from __future__ import print_function
65
65
  import base64
66
66
  import imaplib
67
67
  import json
68
- from optparse import OptionParser
69
68
  import smtplib
70
69
  import sys
71
- import urllib
70
+ from optparse import OptionParser
72
71
 
73
72
  import six
74
73
 
@@ -76,62 +75,81 @@ import six
76
75
  def SetupOptionParser():
77
76
  # Usage message is the module's docstring.
78
77
  parser = OptionParser(usage=__doc__)
79
- parser.add_option('--generate_oauth2_token',
80
- action='store_true',
81
- dest='generate_oauth2_token',
82
- help='generates an OAuth2 token for testing')
83
- parser.add_option('--generate_oauth2_string',
84
- action='store_true',
85
- dest='generate_oauth2_string',
86
- help='generates an initial client response string for '
87
- 'OAuth2')
88
- parser.add_option('--client_id',
89
- default=None,
90
- help='Client ID of the application that is authenticating. '
91
- 'See OAuth2 documentation for details.')
92
- parser.add_option('--client_secret',
93
- default=None,
94
- help='Client secret of the application that is '
95
- 'authenticating. See OAuth2 documentation for '
96
- 'details.')
97
- parser.add_option('--access_token',
98
- default=None,
99
- help='OAuth2 access token')
100
- parser.add_option('--refresh_token',
101
- default=None,
102
- help='OAuth2 refresh token')
103
- parser.add_option('--scope',
104
- default='https://mail.google.com/',
105
- help='scope for the access token. Multiple scopes can be '
106
- 'listed separated by spaces with the whole argument '
107
- 'quoted.')
108
- parser.add_option('--test_imap_authentication',
109
- action='store_true',
110
- dest='test_imap_authentication',
111
- help='attempts to authenticate to IMAP')
112
- parser.add_option('--test_smtp_authentication',
113
- action='store_true',
114
- dest='test_smtp_authentication',
115
- help='attempts to authenticate to SMTP')
116
- parser.add_option('--user',
117
- default=None,
118
- help='email address of user whose account is being '
119
- 'accessed')
120
- parser.add_option('--quiet',
121
- action='store_true',
122
- default=False,
123
- dest='quiet',
124
- help='Omit verbose descriptions and only print '
125
- 'machine-readable outputs.')
78
+ parser.add_option(
79
+ "--generate_oauth2_token",
80
+ action="store_true",
81
+ dest="generate_oauth2_token",
82
+ help="generates an OAuth2 token for testing",
83
+ )
84
+ parser.add_option(
85
+ "--ugo2t", # updated_generate_oauth2_token
86
+ action="store_true",
87
+ dest="updated_generate_oauth2_token",
88
+ help="generates a token and refresh token for a given credentials file from google cloud plataform",
89
+ )
90
+ parser.add_option(
91
+ "--generate_oauth2_string",
92
+ action="store_true",
93
+ dest="generate_oauth2_string",
94
+ help="generates an initial client response string for OAuth2",
95
+ )
96
+ parser.add_option(
97
+ "--client_id",
98
+ default=None,
99
+ help="Client ID of the application that is authenticating. "
100
+ "See OAuth2 documentation for details.",
101
+ )
102
+ parser.add_option(
103
+ "--client_secret",
104
+ default=None,
105
+ help="Client secret of the application that is "
106
+ "authenticating. See OAuth2 documentation for "
107
+ "details.",
108
+ )
109
+ parser.add_option("--access_token", default=None, help="OAuth2 access token")
110
+ parser.add_option("--refresh_token", default=None, help="OAuth2 refresh token")
111
+ parser.add_option(
112
+ "--scope",
113
+ default="https://mail.google.com/",
114
+ help="scope for the access token. Multiple scopes can be "
115
+ "listed separated by spaces with the whole argument "
116
+ "quoted.",
117
+ )
118
+ parser.add_option(
119
+ "--test_imap_authentication",
120
+ action="store_true",
121
+ dest="test_imap_authentication",
122
+ help="attempts to authenticate to IMAP",
123
+ )
124
+ parser.add_option(
125
+ "--test_smtp_authentication",
126
+ action="store_true",
127
+ dest="test_smtp_authentication",
128
+ help="attempts to authenticate to SMTP",
129
+ )
130
+ parser.add_option(
131
+ "--user",
132
+ default=None,
133
+ help="email address of user whose account is being accessed",
134
+ )
135
+ parser.add_option(
136
+ "--quiet",
137
+ action="store_true",
138
+ default=False,
139
+ dest="quiet",
140
+ help="Omit verbose descriptions and only print machine-readable outputs.",
141
+ )
126
142
  return parser
127
143
 
128
144
 
129
145
  # The URL root for accessing Google Accounts.
130
- GOOGLE_ACCOUNTS_BASE_URL = 'https://accounts.google.com'
146
+ GOOGLE_ACCOUNTS_BASE_URL = "https://accounts.google.com"
131
147
 
148
+ # Google tokens scope to restrict applications
149
+ SCOPES = ["https://mail.google.com/"]
132
150
 
133
151
  # Hardcoded dummy redirect URI for non-web apps.
134
- REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
152
+ REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob"
135
153
 
136
154
 
137
155
  def AccountsUrl(command):
@@ -143,12 +161,12 @@ def AccountsUrl(command):
143
161
  Returns:
144
162
  A URL for the given command.
145
163
  """
146
- return '%s/%s' % (GOOGLE_ACCOUNTS_BASE_URL, command)
164
+ return "%s/%s" % (GOOGLE_ACCOUNTS_BASE_URL, command)
147
165
 
148
166
 
149
167
  def UrlEscape(text):
150
168
  # See OAUTH 5.1 for a definition of which characters need to be escaped.
151
- return six.moves.urllib.parse.quote(text, safe='~-._')
169
+ return six.moves.urllib.parse.quote(text, safe="~-._")
152
170
 
153
171
 
154
172
  def UrlUnescape(text):
@@ -167,11 +185,11 @@ def FormatUrlParams(params):
167
185
  """
168
186
  param_fragments = []
169
187
  for param in sorted(params.items(), key=lambda x: x[0]):
170
- param_fragments.append('%s=%s' % (param[0], UrlEscape(param[1])))
171
- return '&'.join(param_fragments)
188
+ param_fragments.append("%s=%s" % (param[0], UrlEscape(param[1])))
189
+ return "&".join(param_fragments)
172
190
 
173
191
 
174
- def GeneratePermissionUrl(client_id, scope='https://mail.google.com/'):
192
+ def GeneratePermissionUrl(client_id, scope="https://mail.google.com/"):
175
193
  """Generates the URL for authorizing access.
176
194
 
177
195
  This uses the "OAuth2 for Installed Applications" flow described at
@@ -184,12 +202,11 @@ def GeneratePermissionUrl(client_id, scope='https://mail.google.com/'):
184
202
  A URL that the user should visit in their browser.
185
203
  """
186
204
  params = {}
187
- params['client_id'] = client_id
188
- params['redirect_uri'] = REDIRECT_URI
189
- params['scope'] = scope
190
- params['response_type'] = 'code'
191
- return '%s?%s' % (AccountsUrl('o/oauth2/auth'),
192
- FormatUrlParams(params))
205
+ params["client_id"] = client_id
206
+ params["redirect_uri"] = REDIRECT_URI
207
+ params["scope"] = scope
208
+ params["response_type"] = "code"
209
+ return "%s?%s" % (AccountsUrl("o/oauth2/auth"), FormatUrlParams(params))
193
210
 
194
211
 
195
212
  def AuthorizeTokens(client_id, client_secret, authorization_code):
@@ -208,15 +225,16 @@ def AuthorizeTokens(client_id, client_secret, authorization_code):
208
225
  fields include 'access_token', 'expires_in', and 'refresh_token'.
209
226
  """
210
227
  params = {}
211
- params['client_id'] = client_id
212
- params['client_secret'] = client_secret
213
- params['code'] = authorization_code
214
- params['redirect_uri'] = REDIRECT_URI
215
- params['grant_type'] = 'authorization_code'
216
- request_url = AccountsUrl('o/oauth2/token')
228
+ params["client_id"] = client_id
229
+ params["client_secret"] = client_secret
230
+ params["code"] = authorization_code
231
+ params["redirect_uri"] = REDIRECT_URI
232
+ params["grant_type"] = "authorization_code"
233
+ request_url = AccountsUrl("o/oauth2/token")
217
234
 
218
235
  response = six.moves.urllib.request.urlopen(
219
- request_url, six.moves.urllib.parse.urlencode(params).encode('utf-8')).read()
236
+ request_url, six.moves.urllib.parse.urlencode(params).encode("utf-8")
237
+ ).read()
220
238
  return json.loads(response)
221
239
 
222
240
 
@@ -234,14 +252,15 @@ def RefreshToken(client_id, client_secret, refresh_token):
234
252
  fields include 'access_token', 'expires_in', and 'refresh_token'.
235
253
  """
236
254
  params = {}
237
- params['client_id'] = client_id
238
- params['client_secret'] = client_secret
239
- params['refresh_token'] = refresh_token
240
- params['grant_type'] = 'refresh_token'
241
- request_url = AccountsUrl('o/oauth2/token')
255
+ params["client_id"] = client_id
256
+ params["client_secret"] = client_secret
257
+ params["refresh_token"] = refresh_token
258
+ params["grant_type"] = "refresh_token"
259
+ request_url = AccountsUrl("o/oauth2/token")
242
260
 
243
261
  response = six.moves.urllib.request.urlopen(
244
- request_url, six.moves.urllib.parse.urlencode(params).encode('utf-8')).read()
262
+ request_url, six.moves.urllib.parse.urlencode(params).encode("utf-8")
263
+ ).read()
245
264
  return json.loads(response)
246
265
 
247
266
 
@@ -258,7 +277,7 @@ def GenerateOAuth2String(username, access_token, base64_encode=True):
258
277
  Returns:
259
278
  The SASL argument for the OAuth2 mechanism.
260
279
  """
261
- auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
280
+ auth_string = "user=%s\1auth=Bearer %s\1\1" % (username, access_token)
262
281
  if base64_encode:
263
282
  auth_string = base64.b64encode(auth_string)
264
283
  return auth_string
@@ -275,10 +294,10 @@ def TestImapAuthentication(user, auth_string):
275
294
  Must not be base64-encoded, since imaplib does its own base64-encoding.
276
295
  """
277
296
  print()
278
- imap_conn = imaplib.IMAP4_SSL('imap.gmail.com')
297
+ imap_conn = imaplib.IMAP4_SSL("imap.gmail.com")
279
298
  imap_conn.debug = 4
280
- imap_conn.authenticate('XOAUTH2', lambda x: auth_string)
281
- imap_conn.select('INBOX')
299
+ imap_conn.authenticate("XOAUTH2", lambda x: auth_string)
300
+ imap_conn.select("INBOX")
282
301
 
283
302
 
284
303
  def TestSmtpAuthentication(user, auth_string):
@@ -290,65 +309,99 @@ def TestSmtpAuthentication(user, auth_string):
290
309
  GenerateOAuth2String.
291
310
  """
292
311
  print()
293
- smtp_conn = smtplib.SMTP('smtp.gmail.com', 587)
312
+ smtp_conn = smtplib.SMTP("smtp.gmail.com", 587)
294
313
  smtp_conn.set_debuglevel(True)
295
- smtp_conn.ehlo('test')
314
+ smtp_conn.ehlo("test")
296
315
  smtp_conn.starttls()
297
- smtp_conn.docmd('AUTH', 'XOAUTH2 ' + base64.b64encode(auth_string))
316
+ smtp_conn.docmd("AUTH", "XOAUTH2 " + base64.b64encode(auth_string))
298
317
 
299
318
 
300
319
  def RequireOptions(options, *args):
301
320
  missing = [arg for arg in args if getattr(options, arg) is None]
302
321
  if missing:
303
- print('Missing options: %s' % ' '.join(missing))
322
+ print("Missing options: %s" % " ".join(missing))
304
323
  sys.exit(-1)
305
324
 
306
325
 
326
+ def UpdatedRefreshTokenGenerator(credentials_path):
327
+ global SCOPES
328
+
329
+ from google_auth_oauthlib.flow import InstalledAppFlow
330
+
331
+ try:
332
+ flow = InstalledAppFlow.from_client_secrets_file(
333
+ credentials_path, # your credentials file from google, download it from gcp
334
+ SCOPES,
335
+ )
336
+
337
+ creds = flow.run_local_server(port=8088)
338
+ return creds
339
+ except OSError as e:
340
+ print(f"[ERROR] PORT ALREADY IN USE: {e}")
341
+
342
+
307
343
  def main():
308
344
  argv = sys.argv
309
345
  options_parser = SetupOptionParser()
310
346
  (options, args) = options_parser.parse_args()
311
347
  if options.refresh_token:
312
- RequireOptions(options, 'client_id', 'client_secret')
313
- response = RefreshToken(options.client_id, options.client_secret,
314
- options.refresh_token)
348
+ RequireOptions(options, "client_id", "client_secret")
349
+ response = RefreshToken(
350
+ options.client_id, options.client_secret, options.refresh_token
351
+ )
315
352
  if options.quiet:
316
- print(response['access_token'])
353
+ print(response["access_token"])
317
354
  else:
318
- print('Access Token: %s' % response['access_token'])
319
- print('Access Token Expiration Seconds: %s' % response['expires_in'])
355
+ print("Access Token: %s" % response["access_token"])
356
+ print("Access Token Expiration Seconds: %s" % response["expires_in"])
320
357
  elif options.generate_oauth2_string:
321
- RequireOptions(options, 'user', 'access_token')
358
+ RequireOptions(options, "user", "access_token")
322
359
  oauth2_string = GenerateOAuth2String(options.user, options.access_token)
323
360
  if options.quiet:
324
361
  print(oauth2_string)
325
362
  else:
326
- print('OAuth2 argument:\n' + oauth2_string)
363
+ print("OAuth2 argument:\n" + oauth2_string)
327
364
  elif options.generate_oauth2_token:
328
- RequireOptions(options, 'client_id', 'client_secret')
329
- print('To authorize token, visit this url and follow the directions:')
330
- print(' %s' % GeneratePermissionUrl(options.client_id, options.scope))
331
- authorization_code = six.moves.input('Enter verification code: ')
332
- response = AuthorizeTokens(options.client_id, options.client_secret,
333
- authorization_code)
334
- print('Refresh Token: %s' % response['refresh_token'])
335
- print('Access Token: %s' % response['access_token'])
336
- print('Access Token Expiration Seconds: %s' % response['expires_in'])
365
+ RequireOptions(options, "client_id", "client_secret")
366
+ print("To authorize token, visit this url and follow the directions:")
367
+ print(" %s" % GeneratePermissionUrl(options.client_id, options.scope))
368
+ authorization_code = six.moves.input("Enter verification code: ")
369
+ response = AuthorizeTokens(
370
+ options.client_id, options.client_secret, authorization_code
371
+ )
372
+ print("Refresh Token: %s" % response["refresh_token"])
373
+ print("Access Token: %s" % response["access_token"])
374
+ print("Access Token Expiration Seconds: %s" % response["expires_in"])
375
+ elif options.updated_generate_oauth2_token:
376
+ RequireOptions(options, "credentials_path")
377
+ print("LogIn to check the authenticity of the requested action")
378
+ creds = UpdatedRefreshTokenGenerator(options.credentials_path)
379
+ if creds:
380
+ print("Token: %s" % creds.token)
381
+ print("Refresh Token: %s" % creds.refresh_token)
382
+ else:
383
+ print("An error occurs, check your gcp project is verified and retry later")
337
384
  elif options.test_imap_authentication:
338
- RequireOptions(options, 'user', 'access_token')
339
- TestImapAuthentication(options.user,
340
- GenerateOAuth2String(options.user, options.access_token,
341
- base64_encode=False))
385
+ RequireOptions(options, "user", "access_token")
386
+ TestImapAuthentication(
387
+ options.user,
388
+ GenerateOAuth2String(
389
+ options.user, options.access_token, base64_encode=False
390
+ ),
391
+ )
342
392
  elif options.test_smtp_authentication:
343
- RequireOptions(options, 'user', 'access_token')
344
- TestSmtpAuthentication(options.user,
345
- GenerateOAuth2String(options.user, options.access_token,
346
- base64_encode=False))
393
+ RequireOptions(options, "user", "access_token")
394
+ TestSmtpAuthentication(
395
+ options.user,
396
+ GenerateOAuth2String(
397
+ options.user, options.access_token, base64_encode=False
398
+ ),
399
+ )
347
400
  else:
348
401
  options_parser.print_help()
349
- print('Nothing to do, exiting.')
402
+ print("Nothing to do, exiting.")
350
403
  return
351
404
 
352
405
 
353
- if __name__ == '__main__':
354
- main()
406
+ if __name__ == "__main__":
407
+ main()
@@ -1,47 +1,60 @@
1
1
  """
2
2
  Email backend that uses the GMail API via OAuth2 authentication.
3
3
  """
4
+
4
5
  import base64
5
6
  import logging
6
7
 
7
- from django.conf import settings
8
- from django.core.mail.backends.base import BaseEmailBackend
9
-
10
8
  import google.oauth2.credentials
11
9
  import googleapiclient.discovery
10
+ from django.conf import settings
11
+ from django.core.mail.backends.base import BaseEmailBackend
12
12
 
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
16
  class GmailBackend(BaseEmailBackend):
17
- def __init__(self, client_id=None, client_secret=None, refresh_token=None,
18
- user_id=None, fail_silently=False, **kwargs):
17
+ def __init__(
18
+ self,
19
+ client_id=None,
20
+ client_secret=None,
21
+ refresh_token=None,
22
+ user_id=None,
23
+ fail_silently=False,
24
+ **kwargs,
25
+ ):
19
26
  super().__init__(fail_silently=fail_silently, **kwargs)
20
27
  self.client_id = client_id or settings.GMAIL_API_CLIENT_ID
21
28
  self.client_secret = client_secret or settings.GMAIL_API_CLIENT_SECRET
22
29
  self.refresh_token = refresh_token or settings.GMAIL_API_REFRESH_TOKEN
23
- if hasattr(settings, 'GMAIL_API_USER_ID'):
30
+ if hasattr(settings, "GMAIL_API_USER_ID"):
24
31
  self.user_id = user_id or settings.GMAIL_API_USER_ID
25
32
  else:
26
- self.user_id = user_id or 'me'
33
+ self.user_id = user_id or "me"
27
34
 
28
35
  credentials = google.oauth2.credentials.Credentials(
29
- 'token',
36
+ "token",
30
37
  refresh_token=self.refresh_token,
31
- token_uri='https://oauth2.googleapis.com/token',
38
+ token_uri="https://oauth2.googleapis.com/token",
32
39
  client_id=self.client_id,
33
- client_secret=self.client_secret
40
+ client_secret=self.client_secret,
41
+ )
42
+ self.service = googleapiclient.discovery.build(
43
+ "gmail", "v1", credentials=credentials, cache_discovery=False
34
44
  )
35
- self.service = googleapiclient.discovery.build('gmail', 'v1', credentials=credentials, cache_discovery=False)
36
45
 
37
46
  def send_message(self, email_message):
38
47
  if not email_message.recipients():
39
48
  return False
40
49
  message = email_message.message()
41
50
  if email_message.bcc:
42
- email_message._set_list_header_if_not_empty(message, 'Bcc', email_message.bcc)
43
- raw_message = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
44
- return self.service.users().messages().send(userId=self.user_id, body=raw_message)
51
+ email_message._set_list_header_if_not_empty(
52
+ message, "Bcc", email_message.bcc
53
+ )
54
+ raw_message = {"raw": base64.urlsafe_b64encode(message.as_bytes()).decode()}
55
+ return (
56
+ self.service.users().messages().send(userId=self.user_id, body=raw_message)
57
+ )
45
58
 
46
59
  def send_messages(self, email_messages):
47
60
  """Send all messages using BatchHttpRequest"""
@@ -53,7 +66,10 @@ class GmailBackend(BaseEmailBackend):
53
66
  def send_callback(r_id, response, exception):
54
67
  nonlocal msg_count, last_exception
55
68
  if exception is not None:
56
- logger.exception('An error occurred sending the message via GMail API: %s', exception)
69
+ logger.exception(
70
+ "An error occurred sending the message via GMail API: %s",
71
+ exception,
72
+ )
57
73
  last_exception = exception
58
74
  else:
59
75
  msg_count += 1
@@ -0,0 +1,51 @@
1
+ import re
2
+ import sys
3
+
4
+ from setuptools import find_packages, setup
5
+
6
+ if sys.version_info < (3, 5):
7
+ raise "must use Python version 3.5 or higher"
8
+
9
+ with open("./gmailapi_backend/__init__.py", "r") as f:
10
+ MATCH_EXPR = "__version__[^'\"]+(['\"])([^'\"]+)"
11
+ VERSION = re.search(MATCH_EXPR, f.read()).group(2).strip()
12
+
13
+
14
+ setup(
15
+ name="django-gmailapi-backend",
16
+ version=VERSION,
17
+ packages=find_packages(),
18
+ author="Michele Dolfi",
19
+ author_email="michele.dolfi@gmail.com",
20
+ license="Apache License 2.0",
21
+ entry_points={
22
+ "console_scripts": [
23
+ "gmail_oauth2 = gmailapi_backend.bin.gmail_oauth2:main",
24
+ ]
25
+ },
26
+ install_requires=[
27
+ "google-api-python-client~=2.0",
28
+ "google-auth>=1.16.0,<3.0.0dev",
29
+ "google-auth-oauthlib>=1.4.0",
30
+ ],
31
+ url="https://github.com/dolfim/django-gmailapi-backend",
32
+ long_description_content_type="text/markdown",
33
+ long_description=open("README.md").read(),
34
+ description="Email backend for Django which sends email via the Gmail API",
35
+ classifiers=[
36
+ "Intended Audience :: Developers",
37
+ "License :: OSI Approved :: Apache Software License",
38
+ "Operating System :: MacOS :: MacOS X",
39
+ "Operating System :: Microsoft :: Windows",
40
+ "Operating System :: POSIX",
41
+ "Programming Language :: Python",
42
+ "Programming Language :: Python :: 3",
43
+ "Programming Language :: Python :: 3.5",
44
+ "Programming Language :: Python :: 3.6",
45
+ "Programming Language :: Python :: 3.7",
46
+ "Programming Language :: Python :: 3.8",
47
+ "Framework :: Django",
48
+ "Topic :: Communications :: Email",
49
+ "Development Status :: 4 - Beta",
50
+ ],
51
+ )
@@ -1 +0,0 @@
1
- __version__ = '0.3.3'
@@ -1,49 +0,0 @@
1
- import re
2
- from setuptools import setup, find_packages
3
-
4
- import sys
5
- if sys.version_info < (3, 5):
6
- raise 'must use Python version 3.5 or higher'
7
-
8
- with open('./gmailapi_backend/__init__.py', 'r') as f:
9
- MATCH_EXPR = "__version__[^'\"]+(['\"])([^'\"]+)"
10
- VERSION = re.search(MATCH_EXPR, f.read()).group(2).strip()
11
-
12
-
13
- setup(
14
- name='django-gmailapi-backend',
15
- version=VERSION,
16
- packages=find_packages(),
17
- author="Michele Dolfi",
18
- author_email="michele.dolfi@gmail.com",
19
- license="Apache License 2.0",
20
- entry_points={
21
- 'console_scripts': [
22
- 'gmail_oauth2 = gmailapi_backend.bin.gmail_oauth2:main',
23
- ]
24
- },
25
- install_requires=[
26
- 'google-api-python-client~=2.0',
27
- 'google-auth>=1.16.0,<3.0.0dev',
28
- ],
29
- url="https://github.com/dolfim/django-gmailapi-backend",
30
- long_description_content_type='text/markdown',
31
- long_description=open('README.md').read(),
32
- description='Email backend for Django which sends email via the Gmail API',
33
- classifiers=[
34
- 'Intended Audience :: Developers',
35
- 'License :: OSI Approved :: Apache Software License',
36
- 'Operating System :: MacOS :: MacOS X',
37
- 'Operating System :: Microsoft :: Windows',
38
- 'Operating System :: POSIX',
39
- 'Programming Language :: Python',
40
- 'Programming Language :: Python :: 3',
41
- 'Programming Language :: Python :: 3.5',
42
- 'Programming Language :: Python :: 3.6',
43
- 'Programming Language :: Python :: 3.7',
44
- 'Programming Language :: Python :: 3.8',
45
- 'Framework :: Django',
46
- 'Topic :: Communications :: Email',
47
- 'Development Status :: 4 - Beta'
48
- ],
49
- )