Skip to main content

Asynchronous email dispatcher microservice with scheduling, rate limiting, attachments, and a FastAPI REST API.

Project description

genro-mail-proxy

PyPI version Tests codecov Documentation Python 3.10+ License

Asynchronous email dispatcher microservice with scheduling, rate limiting, attachments (S3/URL/base64), REST API (FastAPI), and Prometheus metrics.

Why Use an Email Proxy?

Instead of directly connecting to SMTP servers from your application, genro-mail-proxy provides a decoupled, resilient email delivery layer with:

  • 19x faster requests (32ms vs 620ms) - non-blocking async operations
  • 🔄 Never lose messages - automatic retry, guaranteed persistence
  • 🎯 Connection pooling - 10-50x faster for burst sends
  • 📊 Centralized monitoring - Prometheus metrics, not scattered logs
  • 🛡️ Built-in rate limiting - shared across all app instances
  • 🎛️ Priority queuing - immediate/high/medium/low with automatic ordering

See Architecture Overview for detailed comparison with direct SMTP.

Main integration points:

  • REST control plane secured by X-API-Token for queue management and configuration.
  • Outbound proxy_sync call towards Genropy, authenticated via basic auth and configured through [client] in config.ini.
  • Delivery reports and Prometheus metrics to monitor message lifecycle and rate limiting.
  • Unified SQLite storage with a single messages table that tracks queue state (priority, deferred_ts) and delivery lifecycle (sent_ts, error_ts, reported_ts).
  • Background loops:
    • SMTP dispatch loop selects records from messages that lack sent_ts/error_ts and have deferred_ts in the past, enforces rate limits, then stamps sent_ts or error_ts/error.
    • Client report loop batches completed items (sent/error/deferred) that are still missing reported_ts and posts them to the upstream proxy_sync endpoint; on acknowledgement the records receive reported_ts and are later purged according to the retention window.

Quick start

docker build -t genro-mail-proxy .
docker run -p 8000:8000 \
  -e GMP_CLIENT_SYNC_URL=https://your-app/proxy_sync \
  -e GMP_CLIENT_SYNC_USER=syncuser \
  -e GMP_CLIENT_SYNC_PASSWORD=syncpass \
  -e GMP_API_TOKEN=your-secret-token \
  genro-mail-proxy

See config.ini.example for all available environment variables (all prefixed with GMP_).

Example client

A complete integration example is provided in example_client.py. This demonstrates the recommended pattern for integrating with the mail service:

# Install dependencies
pip install fastapi uvicorn aiohttp

# Configure your email address
nano example_config.ini  # Edit recipient_email

# Start the example client
python3 example_client.py

# Send test email
curl -X POST http://localhost:8081/send-test-email

The example shows:

  • Local-first persistence (never lose messages)
  • Async submission to mail service
  • run-now trigger for fast delivery
  • Delivery report handling via proxy_sync

See Example Client Documentation for detailed walkthrough.

Configuration highlights

  • [delivery] exposes delivery_report_retention_seconds to control how long reported messages stay in the messages table (default seven days).
  • /commands/add-messages validates each payload (id, from, to etc.), enqueues valid messages with priority=2 when omitted, and returns a response with queued count plus a rejected list containing {"id","reason"} entries for failures.

Attachment Handling

genro-mail-proxy supports multiple attachment sources with flexible routing.

Storage Path Formats

Format Example Description
base64:content base64:SGVsbG8= Inline base64-encoded content
/absolute/path /tmp/attachments/file.pdf Local filesystem absolute path
relative/path uploads/doc.pdf Filesystem relative to configured base_dir
@params @doc_id=123&version=2 HTTP POST to default endpoint
@[url]params @[https://api.example.com]id=456 HTTP POST to specific URL

Attachment Configuration

[attachments]
# Filesystem fetcher base directory (for relative paths)
base_dir = /var/attachments

# HTTP fetcher default endpoint
http_endpoint = https://api.example.com/attachments
http_auth_method = bearer  # none, bearer, or basic
http_auth_token = your-secret-token
# For basic auth:
# http_auth_user = username
# http_auth_password = password

Attachment Cache

A two-tiered cache (memory + disk) reduces redundant fetches for frequently used attachments.

MD5 Cache Marker

Filenames can include an MD5 hash marker for cache lookup:

report_{MD5:a1b2c3d4e5f6}.pdf

The marker is extracted for cache lookup and removed from the final filename.

Cache Configuration

[attachments]
# Memory cache (LRU)
cache_memory_max_items = 100
cache_memory_ttl_seconds = 3600

# Disk cache (optional, for large files)
cache_disk_dir = /var/cache/mail-proxy
cache_disk_ttl_seconds = 86400

# Files larger than this threshold use disk cache
cache_memory_max_size_bytes = 1048576  # 1MB

Cache Behavior

  • Small files (< cache_memory_max_size_bytes): stored in memory LRU cache
  • Large files: stored on disk if cache_disk_dir is configured
  • Cache lookup: if filename contains {MD5:hash}, cache is checked before fetching
  • Cache population: after fetch, content is cached using computed MD5

Development

pip install -e ".[dev]"
pytest

License

Apache License 2.0 — see LICENSE for details.

Copyright 2025 Softwell S.r.l. — Genropy Team

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

genro_mail_proxy-0.3.5.tar.gz (162.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

genro_mail_proxy-0.3.5-py3-none-any.whl (93.5 kB view details)

Uploaded Python 3

File details

Details for the file genro_mail_proxy-0.3.5.tar.gz.

File metadata

  • Download URL: genro_mail_proxy-0.3.5.tar.gz
  • Upload date:
  • Size: 162.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for genro_mail_proxy-0.3.5.tar.gz
Algorithm Hash digest
SHA256 fc35ff9a45892d873ea8e346589537c4cf79c74896dea534f4ac281e51a49de9
MD5 d619facd4c23c41a619e2b1035c7bc67
BLAKE2b-256 3854170b25c381cb04a46850f24bb97ff8efecd9e24d86cb33f7a7f234c048d7

See more details on using hashes here.

Provenance

The following attestation bundles were made for genro_mail_proxy-0.3.5.tar.gz:

Publisher: publish.yml on genropy/genro-mail-proxy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file genro_mail_proxy-0.3.5-py3-none-any.whl.

File metadata

File hashes

Hashes for genro_mail_proxy-0.3.5-py3-none-any.whl
Algorithm Hash digest
SHA256 439f1185e82c7013a395a79029e789870661be32235e7f1948538fcedcd4f7ee
MD5 faa4e4e10139066787cda1637e76f782
BLAKE2b-256 bfee69428905a690e34ec59ffcbcd62e9adca13dccd3887aa81d3d29070d0fad

See more details on using hashes here.

Provenance

The following attestation bundles were made for genro_mail_proxy-0.3.5-py3-none-any.whl:

Publisher: publish.yml on genropy/genro-mail-proxy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page