work on package prep
git-svn-id: https://vault.zeeksgeeks.com/svn/django_aws_ses/trunk@5 ed966f06-d3d6-432b-bc91-693151a5c6b4
This commit is contained in:
parent
6329154ffa
commit
54b5c97ce9
|
@ -11,7 +11,7 @@ from .models import (
|
|||
|
||||
from . import settings
|
||||
|
||||
logger = settings.logger
|
||||
#logger = settings.logger
|
||||
|
||||
class AwsSesSettingsAdmin(admin.ModelAdmin):
|
||||
model = AwsSesSettings
|
||||
|
@ -44,7 +44,7 @@ admin.site.register(SESStat, SESStatAdmin)
|
|||
|
||||
class AdminEmailListFilter(admin.SimpleListFilter):
|
||||
def queryset(self, request, queryset):
|
||||
logger.info('self.value(): %s' % self.value())
|
||||
#logger.info('self.value(): %s' % self.value())
|
||||
return queryset.filter(email__contains=self.value())
|
||||
|
||||
class BounceRecordAdmin(admin.ModelAdmin):
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.dispatch import Signal
|
|||
|
||||
from datetime import datetime, timedelta
|
||||
from time import sleep
|
||||
import sys
|
||||
|
||||
from . import settings
|
||||
from . import signals
|
||||
|
@ -91,6 +92,23 @@ class SESBackend(BaseEmailBackend):
|
|||
"""Sends one or more EmailMessage objects and returns the number of
|
||||
email messages sent.
|
||||
"""
|
||||
|
||||
|
||||
calling_func = ''
|
||||
try:
|
||||
fcount = 0
|
||||
while sys._getframe(fcount).f_code.co_name in ['send_messages', 'send', 'mail_admins', 'send_mail', 'emit', 'handle']:
|
||||
fcount +=1
|
||||
|
||||
calling_func = sys._getframe(fcount).f_code.co_name
|
||||
|
||||
except Exception as e:
|
||||
logger.info("fcount:%s, called from exception = %s" , (fcount, e))
|
||||
|
||||
logger.info("called from %s" , (calling_func))
|
||||
|
||||
|
||||
|
||||
logger.info("send_messages")
|
||||
if not email_messages:
|
||||
return
|
||||
|
@ -188,6 +206,15 @@ class SESBackend(BaseEmailBackend):
|
|||
|
||||
try:
|
||||
logger.info("Try to send raw email")
|
||||
#logger.info('message.message().as_string() = %s' % message.message().as_string())
|
||||
logger.info("source = %s" % source)
|
||||
logger.info("message.from_email = %s" % self.dkim_key)
|
||||
logger.info("message.recipients() = %s" % message.recipients())
|
||||
|
||||
logger.info("dkim_key = %s" % self.dkim_key)
|
||||
logger.info("dkim_domain = %s" % self.dkim_domain)
|
||||
logger.info("dkim_selector = %s" % self.dkim_selector)
|
||||
logger.info("dkim_headers = %s" % str(self.dkim_headers))
|
||||
response = self.connection.send_raw_email(
|
||||
Source=source or message.from_email,
|
||||
Destinations=message.recipients(),
|
||||
|
|
|
@ -60,7 +60,7 @@ def update_awsses_user(sender, instance, created, **kwargs):
|
|||
if created:
|
||||
AwsSesUserAddon.objects.create(user=instance)
|
||||
try:
|
||||
instance.AwsSesUserAddon.save()
|
||||
instance.aws_ses.save()
|
||||
except AwsSesUserAddon.DoesNotExist:
|
||||
AwsSesUserAddon.objects.create(user=instance)
|
||||
|
||||
|
@ -86,7 +86,7 @@ class BounceRecord(models.Model):
|
|||
reporting_mta = models.CharField(max_length=255, blank=True, null=True,)
|
||||
status = models.CharField(max_length=255, blank=True, null=True,)
|
||||
action = models.CharField(max_length=255, blank=True, null=True,)
|
||||
feedback_id = models.CharField(max_length=255, blank=True, null=True,)
|
||||
feedback_id = models.TextField(max_length=255, blank=True, null=True,)
|
||||
diagnostic_code = models.CharField(max_length=255, blank=True, null=True,)
|
||||
cleared = models.BooleanField(default=False)
|
||||
|
||||
|
@ -97,7 +97,7 @@ class ComplaintRecord(models.Model):
|
|||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
email = models.EmailField()
|
||||
sub_type = models.CharField(max_length=255, blank=True, null=True,)
|
||||
feedback_id = models.CharField(max_length=255, blank=True, null=True,)
|
||||
feedback_id = models.TextField(max_length=255, blank=True, null=True,)
|
||||
feedback_type = models.CharField(max_length=255, blank=True, null=True,)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -116,8 +116,8 @@ class SendRecord(models.Model):
|
|||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
source = models.EmailField()
|
||||
destination = models.EmailField()
|
||||
subject = models.CharField(max_length=255, blank=True, null=True,)
|
||||
message_id = models.CharField(max_length=255, blank=True, null=True,)
|
||||
subject = models.TextField(max_length=255, blank=True, null=True,)
|
||||
message_id = models.TextField(max_length=255, blank=True, null=True,)
|
||||
aws_process_time = models.IntegerField()
|
||||
smtp_response = models.CharField(max_length=255, blank=True, null=True,)
|
||||
status = models.CharField(max_length=255, blank=True, null=True,)
|
||||
|
|
|
@ -5,78 +5,79 @@ import logging
|
|||
from .models import (
|
||||
AwsSesSettings
|
||||
)
|
||||
|
||||
aws_ses_Settings, c = AwsSesSettings.objects.get_or_create(site_id=settings.SITE_ID)
|
||||
|
||||
__all__ = ('ACCESS_KEY', 'SECRET_KEY', 'AWS_SES_REGION_NAME',
|
||||
'AWS_SES_REGION_ENDPOINT', 'AWS_SES_AUTO_THROTTLE',
|
||||
'AWS_SES_RETURN_PATH', 'DKIM_DOMAIN', 'DKIM_PRIVATE_KEY',
|
||||
'DKIM_SELECTOR', 'DKIM_HEADERS', 'TIME_ZONE', 'BASE_DIR',
|
||||
'BOUNCE_LIMIT','SES_BACKEND_DEBUG','SES_BACKEND_DEBUG_LOGFILE_PATH',
|
||||
'SES_BACKEND_DEBUG_LOGFILE_FORMATTER')
|
||||
|
||||
BASE_DIR = getattr(settings, 'BASE_DIR', None)
|
||||
|
||||
if not BASE_DIR:
|
||||
raise RuntimeError('No BASE_DIR defined in project settings, django_aws_ses requires BASE_DIR to be defined and pointed at your root directory. i.e. BASE_DIR = os.path.dirname(os.path.abspath(__file__))')
|
||||
|
||||
DEFAULT_FROM_EMAIL = getattr(settings, 'DEFAULT_FROM_EMAIL', 'no_reply@%s' % aws_ses_Settings.site.domain)
|
||||
|
||||
HOME_URL = getattr(settings, 'HOME_URL', '')
|
||||
|
||||
UNSUBSCRIBE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/unsebscribe.html')
|
||||
BASE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/base.html')
|
||||
|
||||
ACCESS_KEY = aws_ses_Settings.access_key or getattr(settings, 'AWS_SES_ACCESS_KEY_ID',getattr(settings, 'AWS_ACCESS_KEY_ID', None))
|
||||
|
||||
SECRET_KEY = aws_ses_Settings.secret_key or getattr(settings, 'AWS_SES_SECRET_ACCESS_KEY',getattr(settings, 'AWS_SECRET_ACCESS_KEY', None))
|
||||
|
||||
AWS_SES_REGION_NAME = aws_ses_Settings.region_name or getattr(settings, 'AWS_SES_REGION_NAME',getattr(settings, 'AWS_DEFAULT_REGION', 'us-east-1'))
|
||||
|
||||
AWS_SES_REGION_ENDPOINT = aws_ses_Settings.region_endpoint or getattr(settings, 'AWS_SES_REGION_ENDPOINT','email.us-east-1.amazonaws.com')
|
||||
|
||||
AWS_SES_REGION_ENDPOINT_URL = getattr(settings, 'AWS_SES_REGION_ENDPOINT_URL','https://' + AWS_SES_REGION_ENDPOINT)
|
||||
|
||||
AWS_SES_AUTO_THROTTLE = getattr(settings, 'AWS_SES_AUTO_THROTTLE', 0.5)
|
||||
AWS_SES_RETURN_PATH = getattr(settings, 'AWS_SES_RETURN_PATH', None)
|
||||
AWS_SES_CONFIGURATION_SET = getattr(settings, 'AWS_SES_CONFIGURATION_SET', None)
|
||||
|
||||
DKIM_DOMAIN = getattr(settings, "DKIM_DOMAIN", None)
|
||||
DKIM_PRIVATE_KEY = getattr(settings, 'DKIM_PRIVATE_KEY', None)
|
||||
DKIM_SELECTOR = getattr(settings, 'DKIM_SELECTOR', 'ses')
|
||||
DKIM_HEADERS = getattr(settings, 'DKIM_HEADERS',
|
||||
('From', 'To', 'Cc', 'Subject'))
|
||||
|
||||
TIME_ZONE = settings.TIME_ZONE
|
||||
|
||||
VERIFY_BOUNCE_SIGNATURES = getattr(settings, 'AWS_SES_VERIFY_BOUNCE_SIGNATURES', True)
|
||||
|
||||
# Domains that are trusted when retrieving the certificate
|
||||
# used to sign bounce messages.
|
||||
BOUNCE_CERT_DOMAINS = getattr(settings, 'AWS_SNS_BOUNCE_CERT_TRUSTED_DOMAINS', (
|
||||
'amazonaws.com',
|
||||
'amazon.com',
|
||||
))
|
||||
|
||||
SES_BOUNCE_LIMIT = getattr(settings,'BOUNCE_LIMT', 1)
|
||||
|
||||
SES_BACKEND_DEBUG = getattr(settings,'SES_BACKEND_DEBUG', False)
|
||||
try:
|
||||
aws_ses_Settings, c = AwsSesSettings.objects.get_or_create(site_id=settings.SITE_ID)
|
||||
except Exception as e:
|
||||
print("AwsSesSettings does not exist: error: %s" % e)
|
||||
else:
|
||||
__all__ = ('ACCESS_KEY', 'SECRET_KEY', 'AWS_SES_REGION_NAME',
|
||||
'AWS_SES_REGION_ENDPOINT', 'AWS_SES_AUTO_THROTTLE',
|
||||
'AWS_SES_RETURN_PATH', 'DKIM_DOMAIN', 'DKIM_PRIVATE_KEY',
|
||||
'DKIM_SELECTOR', 'DKIM_HEADERS', 'TIME_ZONE', 'BASE_DIR',
|
||||
'BOUNCE_LIMIT','SES_BACKEND_DEBUG','SES_BACKEND_DEBUG_LOGFILE_PATH',
|
||||
'SES_BACKEND_DEBUG_LOGFILE_FORMATTER')
|
||||
|
||||
SES_BACKEND_DEBUG_LOGFILE_PATH = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_PATH', '%s/aws_ses.log' % BASE_DIR)
|
||||
|
||||
SES_BACKEND_DEBUG_LOGFILE_FORMATTER = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_FORMATTER', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
logger = logging.getLogger('django_aws_ses')
|
||||
# logger.setLevel(logging.WARNING)
|
||||
if SES_BACKEND_DEBUG:
|
||||
logger.setLevel(logging.INFO)
|
||||
# create a file handler
|
||||
if SES_BACKEND_DEBUG_LOGFILE_PATH:
|
||||
handler = logging.FileHandler(SES_BACKEND_DEBUG_LOGFILE_PATH)
|
||||
handler.setLevel(logging.INFO)
|
||||
# create a logging format
|
||||
formatter = logging.Formatter(SES_BACKEND_DEBUG_LOGFILE_FORMATTER)
|
||||
handler.setFormatter(formatter)
|
||||
# add the handlers to the logger
|
||||
logger.addHandler(handler)
|
||||
#logger.info('something we are logging')
|
||||
BASE_DIR = getattr(settings, 'BASE_DIR', None)
|
||||
|
||||
if not BASE_DIR:
|
||||
raise RuntimeError('No BASE_DIR defined in project settings, django_aws_ses requires BASE_DIR to be defined and pointed at your root directory. i.e. BASE_DIR = os.path.dirname(os.path.abspath(__file__))')
|
||||
|
||||
DEFAULT_FROM_EMAIL = getattr(settings, 'DEFAULT_FROM_EMAIL', 'no_reply@%s' % aws_ses_Settings.site.domain)
|
||||
|
||||
HOME_URL = getattr(settings, 'HOME_URL', '')
|
||||
|
||||
UNSUBSCRIBE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/unsebscribe.html')
|
||||
BASE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/base.html')
|
||||
|
||||
ACCESS_KEY = aws_ses_Settings.access_key or getattr(settings, 'AWS_SES_ACCESS_KEY_ID',getattr(settings, 'AWS_ACCESS_KEY_ID', None))
|
||||
|
||||
SECRET_KEY = aws_ses_Settings.secret_key or getattr(settings, 'AWS_SES_SECRET_ACCESS_KEY',getattr(settings, 'AWS_SECRET_ACCESS_KEY', None))
|
||||
|
||||
AWS_SES_REGION_NAME = aws_ses_Settings.region_name or getattr(settings, 'AWS_SES_REGION_NAME',getattr(settings, 'AWS_DEFAULT_REGION', 'us-east-1'))
|
||||
|
||||
AWS_SES_REGION_ENDPOINT = aws_ses_Settings.region_endpoint or getattr(settings, 'AWS_SES_REGION_ENDPOINT','email.us-east-1.amazonaws.com')
|
||||
|
||||
AWS_SES_REGION_ENDPOINT_URL = getattr(settings, 'AWS_SES_REGION_ENDPOINT_URL','https://' + AWS_SES_REGION_ENDPOINT)
|
||||
|
||||
AWS_SES_AUTO_THROTTLE = getattr(settings, 'AWS_SES_AUTO_THROTTLE', 0.5)
|
||||
AWS_SES_RETURN_PATH = getattr(settings, 'AWS_SES_RETURN_PATH', None)
|
||||
AWS_SES_CONFIGURATION_SET = getattr(settings, 'AWS_SES_CONFIGURATION_SET', None)
|
||||
|
||||
DKIM_DOMAIN = getattr(settings, "DKIM_DOMAIN", None)
|
||||
DKIM_PRIVATE_KEY = getattr(settings, 'DKIM_PRIVATE_KEY', None)
|
||||
DKIM_SELECTOR = getattr(settings, 'DKIM_SELECTOR', 'ses')
|
||||
DKIM_HEADERS = getattr(settings, 'DKIM_HEADERS', ('From', 'To', 'Cc', 'Subject'))
|
||||
|
||||
TIME_ZONE = settings.TIME_ZONE
|
||||
|
||||
VERIFY_BOUNCE_SIGNATURES = getattr(settings, 'AWS_SES_VERIFY_BOUNCE_SIGNATURES', True)
|
||||
|
||||
# Domains that are trusted when retrieving the certificate
|
||||
# used to sign bounce messages.
|
||||
BOUNCE_CERT_DOMAINS = getattr(settings, 'AWS_SNS_BOUNCE_CERT_TRUSTED_DOMAINS', (
|
||||
'amazonaws.com',
|
||||
'amazon.com',
|
||||
))
|
||||
|
||||
SES_BOUNCE_LIMIT = getattr(settings,'BOUNCE_LIMT', 1)
|
||||
|
||||
SES_BACKEND_DEBUG = getattr(settings,'SES_BACKEND_DEBUG', False)
|
||||
|
||||
SES_BACKEND_DEBUG_LOGFILE_PATH = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_PATH', '%s/aws_ses.log' % BASE_DIR)
|
||||
|
||||
SES_BACKEND_DEBUG_LOGFILE_FORMATTER = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_FORMATTER', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
logger = logging.getLogger('django_aws_ses')
|
||||
# logger.setLevel(logging.WARNING)
|
||||
if SES_BACKEND_DEBUG:
|
||||
logger.setLevel(logging.INFO)
|
||||
# create a file handler
|
||||
if SES_BACKEND_DEBUG_LOGFILE_PATH:
|
||||
handler = logging.FileHandler(SES_BACKEND_DEBUG_LOGFILE_PATH)
|
||||
handler.setLevel(logging.INFO)
|
||||
# create a logging format
|
||||
formatter = logging.Formatter(SES_BACKEND_DEBUG_LOGFILE_FORMATTER)
|
||||
handler.setFormatter(formatter)
|
||||
# add the handlers to the logger
|
||||
logger.addHandler(handler)
|
||||
#logger.info('something we are logging')
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from django.conf.urls import include, url
|
||||
from django.urls import path
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from .views import (
|
||||
|
|
|
@ -17,7 +17,6 @@ User = get_user_model()
|
|||
|
||||
from . import settings
|
||||
from . import signals
|
||||
from . import utils
|
||||
from .models import (
|
||||
BounceRecord,
|
||||
ComplaintRecord
|
||||
|
|
|
@ -365,8 +365,8 @@ def handle_bounce(request):
|
|||
except Exception as e:
|
||||
logger.info("error well trying to get_or_create record: %s" % e)
|
||||
logger.info(
|
||||
u'Received delivery notification: messageId: %s, feedbackType: %s',
|
||||
message_id, feedback_type,
|
||||
u'Received delivery notification: messageId: %s',
|
||||
message_id,
|
||||
extra={
|
||||
'notification': notification,
|
||||
},
|
||||
|
@ -375,7 +375,7 @@ def handle_bounce(request):
|
|||
signals.delivery_received.send(
|
||||
sender=handle_bounce,
|
||||
mail_obj=mail_obj,
|
||||
delivery_obj=delivery_obj,
|
||||
delivery_obj=send_obj,
|
||||
raw_message=raw_json,
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
import ast
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from fnmatch import fnmatchcase
|
||||
|
||||
from distutils.util import convert_path
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
|
||||
def read(*path):
|
||||
return open(os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
||||
*path)).read()
|
||||
|
||||
# Provided as an attribute, so you can append to these instead
|
||||
# of replicating them:
|
||||
standard_exclude = ["*.py", "*.pyc", "*~", ".*", "*.bak"]
|
||||
standard_exclude_directories = [
|
||||
".*", "CVS", "_darcs", "./build",
|
||||
"./dist", "EGG-INFO", "*.egg-info"
|
||||
]
|
||||
|
||||
# Copied from paste/util/finddata.py
|
||||
def find_package_data(where=".", package="", exclude=standard_exclude,
|
||||
exclude_directories=standard_exclude_directories,
|
||||
only_in_packages=True, show_ignored=False):
|
||||
"""
|
||||
Return a dictionary suitable for use in ``package_data``
|
||||
in a distutils ``setup.py`` file.
|
||||
The dictionary looks like::
|
||||
{"package": [files]}
|
||||
Where ``files`` is a list of all the files in that package that
|
||||
don't match anything in ``exclude``.
|
||||
If ``only_in_packages`` is true, then top-level directories that
|
||||
are not packages won't be included (but directories under packages
|
||||
will).
|
||||
Directories matching any pattern in ``exclude_directories`` will
|
||||
be ignored; by default directories with leading ``.``, ``CVS``,
|
||||
and ``_darcs`` will be ignored.
|
||||
If ``show_ignored`` is true, then all the files that aren't
|
||||
included in package data are shown on stderr (for debugging
|
||||
purposes).
|
||||
Note patterns use wildcards, or can be exact paths (including
|
||||
leading ``./``), and all searching is case-insensitive.
|
||||
"""
|
||||
|
||||
out = {}
|
||||
stack = [(convert_path(where), "", package, only_in_packages)]
|
||||
while stack:
|
||||
where, prefix, package, only_in_packages = stack.pop(0)
|
||||
for name in os.listdir(where):
|
||||
fn = os.path.join(where, name)
|
||||
if os.path.isdir(fn):
|
||||
bad_name = False
|
||||
for pattern in exclude_directories:
|
||||
if (fnmatchcase(name, pattern) or
|
||||
fn.lower() == pattern.lower()):
|
||||
bad_name = True
|
||||
if show_ignored:
|
||||
sys.stderr.write("Directory %s ignored by pattern %s" % (fn, pattern))
|
||||
break
|
||||
if bad_name:
|
||||
continue
|
||||
if os.path.isfile(os.path.join(fn, "__init__.py")) \
|
||||
and not prefix:
|
||||
if not package:
|
||||
new_package = name
|
||||
else:
|
||||
new_package = package + "." + name
|
||||
stack.append((fn, "", new_package, False))
|
||||
else:
|
||||
stack.append((fn, prefix + name + "/", package,
|
||||
only_in_packages))
|
||||
elif package or not only_in_packages:
|
||||
# is a file
|
||||
bad_name = False
|
||||
for pattern in exclude:
|
||||
if (fnmatchcase(name, pattern) or
|
||||
fn.lower() == pattern.lower()):
|
||||
bad_name = True
|
||||
if show_ignored:
|
||||
sys.stderr.write("File %s ignored by pattern %s" % (fn, pattern))
|
||||
break
|
||||
if bad_name:
|
||||
continue
|
||||
out.setdefault(package, []).append(prefix + name)
|
||||
return out
|
||||
|
||||
excluded_directories = standard_exclude_directories + ["example", "tests"]
|
||||
package_data = find_package_data(exclude_directories=excluded_directories)
|
||||
|
||||
DESCRIPTION = "A Django email backend for Amazon's Simple Email Service"
|
||||
|
||||
LONG_DESCRIPTION = None
|
||||
try:
|
||||
LONG_DESCRIPTION = open('README.rst').read()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Parse version
|
||||
_version_re = re.compile(r"VERSION\s+=\s+(.*)")
|
||||
with open("django_aws_ses/__init__.py", "rb") as f:
|
||||
version = ".".join(
|
||||
map(str, ast.literal_eval(_version_re.search(f.read().decode("utf-8")).group(1)))
|
||||
)
|
||||
|
||||
CLASSIFIERS = [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Framework :: Django',
|
||||
'Framework :: Django :: 1.11',
|
||||
'Framework :: Django :: 2.0',
|
||||
'Framework :: Django :: 2.1',
|
||||
'Framework :: Django :: 2.2',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
]
|
||||
|
||||
setup(
|
||||
name='django_aws_ses',
|
||||
version=version,
|
||||
packages=find_packages(exclude=['example', 'tests']),
|
||||
package_data=package_data,
|
||||
python_requires='>=2.7',
|
||||
author='ZeeksGeeks',
|
||||
author_email='development@zeeksgeeks.com',
|
||||
url='https://github.com/django-ses/django-ses',
|
||||
license='MIT',
|
||||
description=DESCRIPTION,
|
||||
long_description=LONG_DESCRIPTION,
|
||||
platforms=['any'],
|
||||
classifiers=CLASSIFIERS,
|
||||
install_requires=["boto3>=1.0.0", "pytz>=2016.10", "future>=0.16.0", "django>1.10"],
|
||||
include_package_data=True,
|
||||
extras_require={
|
||||
'bounce': ['requests<3', 'M2Crypto'],
|
||||
},
|
||||
)
|
Loading…
Reference in New Issue