Shared enums and optional PostgreSQL helpers for email workflows
Project description
wr-common-lib
Shared enums, attachment encoding helpers, and optional PostgreSQL write helpers for the email table.
| PyPI | wr-common-lib |
|---|---|
| import | wr_common_lib |
Requires Python 3.12+.
Install
pip install wr-common-lib
pip install "wr-common-lib[db]" # adds async-db-tools
Package layout
src/wr_common_lib/
├── __init__.py # __version__
└── email/
├── __init__.py # public exports
├── constants.py # MailFlow, MailStatus
├── encoding.py # file_to_base64, file_to_attachment
└── db_oper.py # EmailDbOper, get_email_content_hash
Enums
MailFlow and MailStatus match PostgreSQL mail_flow / mail_status.
from wr_common_lib.email import MailFlow, MailStatus
MailFlow.INBOUND
MailStatus.PENDING.value
Status flows
Outbound: PENDING → SENT | FAILED;webhook → DELIVERED | BOUNCED
Inbound: RECEIVED → PARSED | PARSE_FAILED
Content hash
from wr_common_lib.email import get_email_content_hash
content_hash = get_email_content_hash(
to="a@example.com,b@example.com",
subject="...",
content="...",
cc="",
attachments=[{"filename": "report.pdf"}],
)
Normalizes to / cc (comma-separated), strips subject/content, and hashes attachment filenames only (not file bytes).
Attachment encoding
No [db] extra required. Converts local files to Base64 for Resend attachments[].content or queue tasks.
from wr_common_lib.email import file_to_base64, file_to_attachment
b64 = file_to_base64("/path/to/report.pdf")
att = file_to_attachment("/path/to/report.pdf")
# {"filename": "report.pdf", "content": "<base64>", "content_type": "application/pdf"}
att = file_to_attachment(
"/path/to/data.bin",
filename="custom.pdf",
content_type="application/pdf",
)
EmailDbOper
Requires the [db] extra. Pass an async-db-tools PostgresPool (or compatible pool with fetchval / execute).
from wr_common_lib.email import EmailDbOper, MailFlow, MailStatus, get_email_content_hash
db_oper = EmailDbOper(pool)
Write operations only; reads should use db_oper._db directly (e.g. fetchrow, fetchval).
insert_email
email_id, created = await db_oper.insert_email(
task,
MailFlow.OUTBOUND,
MailStatus.PENDING,
)
# created is True when a new row was inserted, False when content_hash already existed
Task fields (inbound and outbound use the same shape):
| Field | Required | Notes |
|---|---|---|
imo |
yes | |
voyage_id |
yes | UUID string |
mail_from |
yes | Sender |
to |
yes | Recipients (comma-separated allowed) |
cc |
no | Default "" |
subject |
no | Default "" |
content |
no | Default "" |
attachments |
no | List of dicts with filename |
content_hash |
no | Computed via get_email_content_hash when omitted |
created_user_id |
no | Outbound only |
Stored as DB columns mail_to, mail_cc, attachment (jsonb).
On duplicate content_hash, the insert is skipped (ON CONFLICT DO NOTHING); the existing row id is returned and created is False.
Example:
task = {
"imo": 1234567,
"voyage_id": "550e8400-e29b-41d4-a716-446655440000",
"mail_from": "ship@example.com",
"to": "inbox@example.com",
"cc": "",
"subject": "Noon report",
"content": "...",
"attachments": [],
}
email_id, created = await db_oper.insert_email(
task, MailFlow.INBOUND, MailStatus.RECEIVED
)
update_status
await db_oper.update_status(email_id, MailStatus.SENT)
await db_oper.update_status(email_id, MailStatus.DELIVERED)
await db_oper.update_status(email_id, MailStatus.FAILED)
update_parsed_data
Sets mail_status to PARSED and writes parsed_data (jsonb).
await db_oper.update_parsed_data(email_id, {"parsed": "..."})
Dependencies
| install | brings in |
|---|---|
wr-common-lib |
enums, get_email_content_hash, file_to_base64, file_to_attachment |
wr-common-lib[db] |
above + async-db-tools (for EmailDbOper) |
Your application owns the database URL and pool lifecycle.
Publish
pip install -e ".[db]"
# 1. Update CHANGELOG.md for the new version
# 2. Bump version and publish
uv version 0.1.7
export UV_PUBLISH_TOKEN=pypi-...
uv build && uv publish
git tag v0.1.7 && git push --tags # optional: GitHub Release notes from CHANGELOG
PyPI does not allow re-uploading the same version.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wr_common_lib-0.1.6.tar.gz.
File metadata
- Download URL: wr_common_lib-0.1.6.tar.gz
- Upload date:
- Size: 5.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7daff0e78b58c088fd248e4b953130074d0671ad8de935660cb233495a21dd8c
|
|
| MD5 |
e7d68c2b189893a07d95f7cd60b249bd
|
|
| BLAKE2b-256 |
89da143be44819d6771c9626e8682d7a5342858bfbb2cc94f4066e14345e17c4
|
File details
Details for the file wr_common_lib-0.1.6-py3-none-any.whl.
File metadata
- Download URL: wr_common_lib-0.1.6-py3-none-any.whl
- Upload date:
- Size: 6.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce37a71789f4d57a4e14be35dcf1c429397f6e9c8a39fb0e2a24e514208a2c32
|
|
| MD5 |
f4fdc329f34bd1db926d3be5e62bf19b
|
|
| BLAKE2b-256 |
cd1328008a0274ccd892d51c1b2547847270c29a8d58c04c119499b57cbcf595
|