more updates on the deployment stuff

This commit is contained in:
Raymond Jessop 2025-04-18 14:06:39 -05:00
parent a5a7344d3b
commit 06fcb36121
6 changed files with 172 additions and 178 deletions

48
.gitignore vendored
View File

@ -1,16 +1,38 @@
# environment directory
.venv/
.pydevproject
# Python
*.pyc
__pycache__/
*.pyo
*.pyd
.Python
*.egg-info/
dist/
build/
env/
/.project
/logs
/media
/static
__pycache__
/*/migrations
.venv/
*.egg
# Django
*.log
*.pot
*.sqlite3
media/
static/
migrations/
*.code-workspace
.env/
# IDE/Editor
.vscode/
memory-bank/
.cursor/rules/
run/celery/
.pydevproject
.project
.idea/
*.sublime-project
*.sublime-workspace
# OS/Environment
.DS_Store
.env
*.bak
*~
# Package-specific
aws_ses.log

37
LICENSE
View File

@ -1,22 +1,21 @@
Copyright (c) 2011 Harry Marr
MIT License
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
Copyright (c) 2025 ZeeksGeeks
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4
MANIFEST.in Normal file
View File

@ -0,0 +1,4 @@
include LICENSE
include README.md
recursive-include django_aws_ses/templates *.html
recursive-include django_aws_ses/static *.css *.js

View File

@ -0,0 +1,71 @@
# Django AWS SES
A Django email backend for sending emails via Amazon Simple Email Service (SES).
## Features
- Send emails using AWS SES with DKIM signing support.
- Handle bounce, complaint, and delivery notifications via SNS webhooks.
- Filter recipients based on bounce/complaint history and domain validation.
- Admin dashboard for SES statistics and verified emails.
- Unsubscribe functionality with secure URL generation.
## Installation
```bash
pip install django_aws_ses
```
## Requirements
- Python 3.8+
- Django 3.2+
- AWS SES account with verified domains/emails
## Setup
1. Add to `INSTALLED_APPS`:
```python
INSTALLED_APPS = [
...
'django_aws_ses',
]
```
2. Configure settings in `settings.py`:
```python
AWS_SES_ACCESS_KEY_ID = 'your-access-key'
AWS_SES_SECRET_ACCESS_KEY = 'your-secret-key'
AWS_SES_REGION_NAME = 'us-east-1'
AWS_SES_REGION_ENDPOINT = 'email.us-east-1.amazonaws.com'
EMAIL_BACKEND = 'django_aws_ses.backends.SESBackend'
```
3. Apply migrations:
```bash
python manage.py migrate
```
4. (Optional) Enable DKIM signing:
```python
DKIM_DOMAIN = 'example.com'
DKIM_PRIVATE_KEY = 'your-private-key'
DKIM_SELECTOR = 'ses'
```
5. Set up SNS webhook for bounce/complaint handling:
- Add the URL `your-domain.com/aws_ses/bounce/` to your SNS subscription.
- Ensure the view is accessible (e.g., CSRF-exempt).
## Usage
- Send emails using Djangos `send_mail` or `EmailMessage`.
- View SES statistics at `/aws_ses/status/` (superuser only).
- Unsubscribe users via `/aws_ses/unsubscribe/<uuid>/<hash>/`.
## Development
To contribute:
1. Clone the repo: `git clone https://github.com/zeeksgeeks/django_aws_ses`
2. Install dependencies: `pip install -r requirements.txt`
3. Run tests: `python manage.py test`
## License
MIT License. See [LICENSE](LICENSE) for details.
## Credits
Developed by Ray Jessop. Inspired by [django-ses](https://github.com/django-ses/django-ses).

View File

@ -1,8 +1,8 @@
"""Django AWS SES: A Django email backend for Amazon SES."""
default_app_config = 'django_aws_ses.apps.DjangoAwsSesBackendConfig'
# When changing this, remember to change it in setup.py
VERSION = (0, 0, 1)
__version__ = '.'.join([str(x) for x in VERSION])
VERSION = (0, 1, 0)
__version__ = '.'.join(str(x) for x in VERSION)
__author__ = 'Ray Jessop'
__all__ = ('Django AWS SES Backend',)
__all__ = ('SESBackend', 'DjangoAwsSesBackendConfig')

176
setup.py
View File

@ -1,147 +1,45 @@
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',
]
with open("README.md", "r", encoding="utf-8") as f:
long_description = f.read()
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"],
name="django_aws_ses",
version="0.1.0",
packages=find_packages(exclude=["tests"]),
include_package_data=True,
python_requires=">=3.8",
install_requires=[
"django>=3.2",
"boto3>=1.18",
"requests>=2.25",
"cryptography>=3.4",
"dnspython>=2.1",
"pytz>=2021.1",
],
extras_require={
'bounce': ['requests<3', 'M2Crypto'],
"dkim": ["dkimpy>=1.0"],
},
author="Ray Jessop",
author_email="development@zeeksgeeks.com",
description="A Django email backend for Amazon SES",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/zeeksgeeks/django_aws_ses",
license="MIT",
classifiers=[
"Development Status :: 4 - Beta",
"Framework :: Django",
"Framework :: Django :: 3.2",
"Framework :: Django :: 4.0",
"Framework :: Django :: 4.2",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Communications :: Email",
],
)