Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
kalekseev committed Jul 10, 2024
0 parents commit f632b46
Show file tree
Hide file tree
Showing 24 changed files with 1,533 additions and 0 deletions.
142 changes: 142 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
name: jemail CI

on:
push:
branches:
- main
tags:
- v*
pull_request:

jobs:
tests:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
PYTHONPATH: "src"
strategy:
matrix:
# https://github.com/actions/python-versions/blob/main/versions-manifest.json
python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13.0-beta.3"]
django-version:
- "Django>=4.2,<5.0"
- "Django>=5.0,<5.1"
- "Django==5.1b1"
exclude:
- django-version: "Django>=5.0,<5.1"
python-version: 3.8
- django-version: "Django>=5.0,<5.1"
python-version: 3.9
- django-version: "Django==5.1b1"
python-version: 3.8
- django-version: "Django==5.1b1"
python-version: 3.9
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
if: "!endsWith(matrix.python-version, '-dev')"
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: Install deps
run: |
python -m pip install -e .[test]
python -m pip install "${{ matrix.django-version }}" ${{ matrix.drf }}
- run: pytest

lint:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
PYTHONPATH: "src"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}
- run: python -m pip install -e .[dev]
- run: pre-commit run --show-diff-on-failure --color=always --all-files

package:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: Install dependencies
run: |
python -m pip install hatch
- name: Package
run: python -m hatch build
- name: Upload dist
uses: actions/upload-artifact@v4
with:
name: dist
path: dist

publish:
runs-on: ubuntu-latest
needs: [package, tests, lint]
if: startsWith(github.ref, 'refs/tags/v')
timeout-minutes: 5
environment: release
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set release env
id: release_output
run: |
VERSION="${GITHUB_REF:11}"
BODY=$(awk -v RS='### ' '/'$VERSION'.*/ {print $0}' CHANGELOG.md)
if [[ -z "$BODY" ]]; then
echo "No changelog record for version $VERSION."
fi
BODY="${BODY//'%'/'%25'}"
BODY="${BODY//$'\n'/'%0A'}"
BODY="${BODY//$'\r'/'%0D'}"
echo "::set-output name=VERSION::${VERSION}"
echo "::set-output name=BODY::${BODY}"
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Download dist
uses: actions/download-artifact@v4
with:
name: dist
path: dist
- name: Install dependencies
run: |
python -m pip install twine
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: Publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
twine upload dist/*
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ steps.release_output.outputs.VERSION }}
body: ${{ steps.release_output.outputs.BODY }}
draft: false
prerelease: ${{ contains(steps.release_output.outputs.VERSION, 'rc') || contains(steps.release_output.outputs.VERSION, 'b') || contains(steps.release_output.outputs.VERSION, 'a') }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.coverage
.envrc
29 changes: 29 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.1
hooks:
- id: ruff
language: system
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
language: system

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: debug-statements
- id: check-added-large-files
- id: check-merge-conflict
- id: mixed-line-ending
args: ["--fix=lf"]

- repo: local
hooks:
- id: mypy
name: mypy
language: system
entry: mypy
args: [src, tests]
pass_filenames: false
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Change Log

### Unreleased

- Initial release
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 Konstantin Alekseev

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 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.
84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Jemail

Django app to store emails in db


## Installation

```sh
pip install jemail
pip install django-anymail[sendgrid]
```

Anymail used as email backend, for now jemail tested only with `sendgrid` backend.

Update settings with:

```python
EMAIL_BACKEND = "anymail.backends.sendgrid.EmailBackend"

# defaults
JEMAIL = {
"METADATA_ID_KEY": "message_id", # tag name for EmailMessage.pk in message metadata
"HTML_MESSAGE_UPLOAD_TO": "emails/messages/", # path to save html messages to
"ATTACHMENT_UPLOAD_TO": "emails/attachments/", # path to save attachments to
# "IMPORT_HTML_MESSAGE_UPLOAD_TO": "myproject.utils.message_upload_to", # callable option
# "IMPORT_ATTACHMENT_UPLOAD_TO": "myproject.utils.attachment_upload_to", # callable option
}
```

## Usage

```python
from jemail import EmailMessage, EmailAttachment

# save email in db
message = EmailMessage.objects.create_with_objects(
from_email='[email protected]',
to=['[email protected]'],
subject='Subject',
body='Hi User,...',
html_message='<p>Hi User...',
cc=['[email protected]'],
reply_to='[email protected]',
attachments=[EmailAttachment.objects.create(
filename='doc.pdf',
mimetype='application/pdf',
file=ContentFile(b'...', name='doc.pdf')
)],

# build EmailMultiAlternatives from db
msg = message.build_message()
# send email
msg.send()
)
```

## Development

nix-direnv:

```sh
echo "use flake" >> .envrc
direnv allow
app.install
pytest
```

nix:

```sh
nix develop
app.install
pytest
```

uv:

```sh
uv -q venv .venv
source .venv/bin/activate
uv pip install -e .[dev,test]
pre-commit install
pytest
```
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
description = "jemail";

inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};

outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs { inherit system; };
app-test = pkgs.writeShellScriptBin "app.test" ''pytest $@'';
app-install = pkgs.writeShellScriptBin "app.install" ''uv pip install -e .[dev,test] && pre-commit install'';
app-lint = pkgs.writeShellScriptBin "app.lint" ''pre-commit run -a'';
in
{
devShells.default = pkgs.mkShell {
packages = [
pkgs.python312
pkgs.uv
pkgs.pyright
];
buildInputs = [
app-test
app-install
app-lint
];
shellHook = ''
export PYTHONUNBUFFERED=1;
export PYTHONPATH=src;
export DJANGO_SETTINGS_MODULE=tests.settings;
export VIRTUAL_ENV="$(pwd)/.venv"
[[ -d $VIRTUAL_ENV ]] || uv -q venv $VIRTUAL_ENV
export PATH="$VIRTUAL_ENV/bin":$PATH
'';
};
}
);
}
Loading

0 comments on commit f632b46

Please sign in to comment.