mailmail 0.1.0__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.
- mailmail-0.1.0/.github/dependabot.yml +17 -0
- mailmail-0.1.0/.github/workflows/check.yml +117 -0
- mailmail-0.1.0/.github/workflows/publish.yml +34 -0
- mailmail-0.1.0/.gitignore +22 -0
- mailmail-0.1.0/LICENSE +21 -0
- mailmail-0.1.0/PKG-INFO +487 -0
- mailmail-0.1.0/README.ko.md +424 -0
- mailmail-0.1.0/README.md +458 -0
- mailmail-0.1.0/pyproject.toml +80 -0
- mailmail-0.1.0/scripts/check_blocked_list.py +85 -0
- mailmail-0.1.0/skills/send/SKILL.md +214 -0
- mailmail-0.1.0/src/mailmail/__init__.py +268 -0
- mailmail-0.1.0/src/mailmail/__main__.py +11 -0
- mailmail-0.1.0/src/mailmail/account.py +31 -0
- mailmail-0.1.0/src/mailmail/attachment.py +593 -0
- mailmail-0.1.0/src/mailmail/cli.py +358 -0
- mailmail-0.1.0/src/mailmail/config.py +229 -0
- mailmail-0.1.0/src/mailmail/contacts.py +78 -0
- mailmail-0.1.0/src/mailmail/credentials.py +270 -0
- mailmail-0.1.0/src/mailmail/errors.py +140 -0
- mailmail-0.1.0/src/mailmail/mailer.py +396 -0
- mailmail-0.1.0/src/mailmail/message.py +283 -0
- mailmail-0.1.0/src/mailmail/provider.py +124 -0
- mailmail-0.1.0/src/mailmail/py.typed +0 -0
- mailmail-0.1.0/tests/__init__.py +6 -0
- mailmail-0.1.0/tests/conftest.py +161 -0
- mailmail-0.1.0/tests/test_attachment.py +720 -0
- mailmail-0.1.0/tests/test_cli.py +353 -0
- mailmail-0.1.0/tests/test_config.py +221 -0
- mailmail-0.1.0/tests/test_construction.py +45 -0
- mailmail-0.1.0/tests/test_contacts.py +130 -0
- mailmail-0.1.0/tests/test_credentials.py +370 -0
- mailmail-0.1.0/tests/test_docstrings.py +135 -0
- mailmail-0.1.0/tests/test_mailer.py +496 -0
- mailmail-0.1.0/tests/test_message.py +241 -0
- mailmail-0.1.0/tests/test_packaging.py +60 -0
- mailmail-0.1.0/tests/test_readme.py +156 -0
- mailmail-0.1.0/tests/test_send.py +137 -0
- mailmail-0.1.0/tests/test_send_bulk.py +264 -0
- mailmail-0.1.0/tests/test_skill.py +201 -0
- mailmail-0.1.0/tests/test_tls.py +161 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: github-actions
|
|
4
|
+
directory: /
|
|
5
|
+
# Monthly and grouped into one pull request, because the alternative is a
|
|
6
|
+
# treadmill: setup-uv ships several releases some weeks, nearly all of them
|
|
7
|
+
# just checksums for a newly released uv, and a pull request per release on
|
|
8
|
+
# a two-action workflow would be noise that gets skimmed and then ignored.
|
|
9
|
+
# Once a month is often enough for what this has to catch: the major bumps,
|
|
10
|
+
# which an exact pin cannot follow at all.
|
|
11
|
+
schedule:
|
|
12
|
+
interval: monthly
|
|
13
|
+
groups:
|
|
14
|
+
actions:
|
|
15
|
+
patterns: ["*"]
|
|
16
|
+
commit-message:
|
|
17
|
+
prefix: build
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
name: check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "0 0 * * 1"
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
check:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
# The floor and the current release. requires-python says >=3.11, so 3.11 is
|
|
18
|
+
# the version that claim has to actually hold on. Nothing pins the upper end
|
|
19
|
+
# -- >=3.11 promises every release above it, with no ceiling to read off --
|
|
20
|
+
# so it tracks whatever CPython currently ships: left behind, it stops being
|
|
21
|
+
# evidence the promise holds on new releases and becomes a version nobody runs.
|
|
22
|
+
python-version: ["3.11", "3.14"]
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
# Both pinned past a moving tag: @v7 is a pointer its owner can repoint, and the
|
|
26
|
+
# next run here would execute the new target without a commit of its own. The two
|
|
27
|
+
# forms differ because the actions do -- setup-uv publishes no moving tag from v8
|
|
28
|
+
# on and marks its releases immutable, so the version itself cannot move, while
|
|
29
|
+
# checkout's releases stay mutable and only the commit is fixed. Neither follows
|
|
30
|
+
# a new release on its own; dependabot proposes both (.github/dependabot.yml).
|
|
31
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
32
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
33
|
+
|
|
34
|
+
- name: Install
|
|
35
|
+
# A venv per matrix version, not `uv pip --system`: the runner's system
|
|
36
|
+
# Python is externally managed and is 3.12 whatever the matrix says, so
|
|
37
|
+
# --system both failed and ignored the version under test. This is also
|
|
38
|
+
# exactly what the README tells a person to run.
|
|
39
|
+
run: |
|
|
40
|
+
uv venv --python ${{ matrix.python-version }}
|
|
41
|
+
uv pip install -e ".[dev]"
|
|
42
|
+
.venv/bin/python -c "import sys; print('testing on', sys.version)"
|
|
43
|
+
|
|
44
|
+
- name: Test
|
|
45
|
+
run: .venv/bin/pytest -q
|
|
46
|
+
|
|
47
|
+
- name: Lint
|
|
48
|
+
run: .venv/bin/ruff check src tests scripts
|
|
49
|
+
|
|
50
|
+
- name: Types
|
|
51
|
+
run: .venv/bin/mypy
|
|
52
|
+
|
|
53
|
+
- name: Confirm the package still has no runtime dependencies
|
|
54
|
+
# The zero-dependency claim is in the README and the pyproject comment; a
|
|
55
|
+
# claim nothing checks is a claim that quietly stops being true. Installed
|
|
56
|
+
# into a bare environment, mailmail must import with nothing else present.
|
|
57
|
+
run: |
|
|
58
|
+
uv venv /tmp/bare --python ${{ matrix.python-version }}
|
|
59
|
+
uv pip install --python /tmp/bare/bin/python .
|
|
60
|
+
/tmp/bare/bin/python -c "
|
|
61
|
+
import importlib.metadata as md
|
|
62
|
+
requires = md.requires('mailmail') or []
|
|
63
|
+
runtime = [r for r in requires if 'extra ==' not in r]
|
|
64
|
+
assert not runtime, f'runtime dependencies appeared: {runtime}'
|
|
65
|
+
import mailmail
|
|
66
|
+
print('mailmail', mailmail.__version__, 'imports with no third-party packages')
|
|
67
|
+
"
|
|
68
|
+
|
|
69
|
+
- name: Confirm the console script installed
|
|
70
|
+
# pyproject declares a `mailmail` entry point; a wheel that dropped it
|
|
71
|
+
# would leave the CLI, the skill, and the docs pointing at a command that
|
|
72
|
+
# is not there. `--version` is the cheapest call that proves it runs.
|
|
73
|
+
run: |
|
|
74
|
+
uv venv /tmp/cli --python ${{ matrix.python-version }}
|
|
75
|
+
uv pip install --python /tmp/cli/bin/python .
|
|
76
|
+
/tmp/cli/bin/mailmail --version
|
|
77
|
+
|
|
78
|
+
- name: Confirm a user's type checker can see the hints
|
|
79
|
+
# Every hint in this package is invisible to a user unless py.typed ships
|
|
80
|
+
# alongside it (PEP 561), and the source cannot answer whether it did:
|
|
81
|
+
# src/mailmail/py.typed can sit there in git while the built wheel omits it.
|
|
82
|
+
# So ask it the way a user does -- install the built package into a clean
|
|
83
|
+
# environment and run their checker over their code. It shipped without the
|
|
84
|
+
# marker once, which made `to` being required a promise that held only
|
|
85
|
+
# inside this repo.
|
|
86
|
+
run: |
|
|
87
|
+
uv venv /tmp/typed --python ${{ matrix.python-version }}
|
|
88
|
+
uv pip install --python /tmp/typed/bin/python . mypy
|
|
89
|
+
cat > /tmp/user_code.py <<'PY'
|
|
90
|
+
from mailmail import Message, send
|
|
91
|
+
|
|
92
|
+
Message(subject="s", body="b", to="lead@example.com") # 16 recipients
|
|
93
|
+
send(subject="s", body="b") # no recipient
|
|
94
|
+
PY
|
|
95
|
+
/tmp/typed/bin/mypy /tmp/user_code.py > /tmp/mypy_out 2>&1 || true
|
|
96
|
+
cat /tmp/mypy_out
|
|
97
|
+
grep -q 'incompatible type "str"' /tmp/mypy_out
|
|
98
|
+
grep -q 'Missing named argument "to"' /tmp/mypy_out
|
|
99
|
+
|
|
100
|
+
blocked-list-drift:
|
|
101
|
+
# The size limit is asked of the server on every send, so it cannot go stale.
|
|
102
|
+
# The blocked-extension list can: it is a snapshot of what Google published,
|
|
103
|
+
# and Google can change it without telling anyone. This is the only part of
|
|
104
|
+
# what the package knows that has no way of noticing it went wrong.
|
|
105
|
+
#
|
|
106
|
+
# Weekly and on demand, never on a push: a code change is not the reason the
|
|
107
|
+
# list would move, and a Google page edit must not turn someone's pull
|
|
108
|
+
# request red.
|
|
109
|
+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
113
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
114
|
+
- run: |
|
|
115
|
+
uv venv
|
|
116
|
+
uv pip install -e .
|
|
117
|
+
- run: .venv/bin/python scripts/check_blocked_list.py
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
# Publish to PyPI when a GitHub Release is published. Authentication is PyPI
|
|
4
|
+
# Trusted Publishing (OIDC): no token or password is stored anywhere -- GitHub
|
|
5
|
+
# mints a short-lived identity that PyPI verifies against the publisher
|
|
6
|
+
# registered for this repo (owner seokhoonj / repo mailmail / workflow
|
|
7
|
+
# publish.yml / environment "pypi"). Register that publisher on PyPI first; until
|
|
8
|
+
# the project exists there it is registered as a "pending" publisher.
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
release:
|
|
12
|
+
types: [published]
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
publish:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
environment: pypi
|
|
18
|
+
permissions:
|
|
19
|
+
# Naming any permission drops every unnamed one to `none`, so `contents`
|
|
20
|
+
# has to be listed back: checkout clones with the job token, and this repo
|
|
21
|
+
# is private, so without read here that clone fails "repository not found".
|
|
22
|
+
contents: read
|
|
23
|
+
id-token: write # required for OIDC; this is what replaces a stored token
|
|
24
|
+
steps:
|
|
25
|
+
# Pinned the same way check.yml is: checkout past its mutable tag to a
|
|
26
|
+
# commit, setup-uv on its immutable v8 tag, and the publish action past its
|
|
27
|
+
# moving release/v1 branch to a commit. dependabot proposes all three
|
|
28
|
+
# (.github/dependabot.yml). uv build writes the sdist and wheel to dist/,
|
|
29
|
+
# which the publish action uploads.
|
|
30
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
31
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
32
|
+
- name: Build sdist and wheel
|
|
33
|
+
run: uv build
|
|
34
|
+
- uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# AI coding agents
|
|
2
|
+
CLAUDE.md
|
|
3
|
+
.claude/
|
|
4
|
+
AGENTS.md
|
|
5
|
+
AGENT.md
|
|
6
|
+
.codex/
|
|
7
|
+
GEMINI.md
|
|
8
|
+
.gemini/
|
|
9
|
+
|
|
10
|
+
dev/
|
|
11
|
+
|
|
12
|
+
# Python
|
|
13
|
+
__pycache__/
|
|
14
|
+
*.py[cod]
|
|
15
|
+
*.egg-info/
|
|
16
|
+
build/
|
|
17
|
+
dist/
|
|
18
|
+
.venv/
|
|
19
|
+
venv/
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
.mypy_cache/
|
mailmail-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Seokhoon Joo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|