Skip to main content

Email plugin for Pyxle: one mail.service over SMTP, Resend, or any MailProvider, with a logs-instead-of-sends dev mode.

Project description

pyxle-mail

Email for Pyxle apps through one mail.service. Write await mail.send(...) once; deliver it over SMTP, Resend, or any provider that implements the MailProvider contract — swap providers by config, not code. With no configuration it logs instead of sending, so local dev works with zero setup.

Install

pip install pyxle-mail                # SMTP + console need nothing else
pip install "pyxle-mail[resend]"      # + httpx, for the Resend provider

Quickstart

Declare the plugin (it depends on nothing, so order doesn't matter):

{ "plugins": ["pyxle-db", "pyxle-auth", "pyxle-mail"] }

Send from any loader, action, or API route:

from pyxle_mail import get_mail_service

@action
async def invite(request):
    await get_mail_service().send(
        to="user@example.com",
        subject="You're invited",
        html="<p>Welcome aboard.</p>",
        text="Welcome aboard.",
    )
    return {"ok": True}

Out of the box that logs the email (console provider) — no account, key, or SMTP server. Configure a provider when you want real delivery.

Providers

Provider When Needs
console Local dev, dry-run — logs a summary, sends nothing. The default. nothing
smtp Any mail server (Gmail, Fastmail, MailHog, a corporate relay). host (+ usually user/password)
resend Resend — modern transactional API. pyxle-mail[resend] + API key

A provider is just an object with a name and async send(message). Implement pyxle_mail.MailProvider to add your own (SendGrid, Mailgun, SES, Postmark, …) and pass it in — that's how the ecosystem grows providers without touching app code.

Settings

Configure in pyxle.config.json (camelCase) or with PYXLE_MAIL_* environment variables. Precedence is config > env > default. Keep secrets (SMTP password, API key) in the environment, not the committed config.

Config key Env variable Default What it does
fromAddress PYXLE_MAIL_FROM Default sender. Required for any real provider.
fromName PYXLE_MAIL_FROM_NAME Optional display name.
replyTo PYXLE_MAIL_REPLY_TO Default Reply-To.
provider PYXLE_MAIL_PROVIDER "console" console | smtp | resend.
dryRun PYXLE_MAIL_DRY_RUN false Force the console provider regardless of provider — the safe switch for staging.
smtpHost PYXLE_MAIL_SMTP_HOST SMTP server host.
smtpPort PYXLE_MAIL_SMTP_PORT 587 SMTP port.
smtpUsername PYXLE_MAIL_SMTP_USERNAME SMTP auth user.
smtpPassword PYXLE_MAIL_SMTP_PASSWORD SMTP auth password (env only).
smtpUseTls PYXLE_MAIL_SMTP_TLS true STARTTLS (port 587).
smtpUseSsl PYXLE_MAIL_SMTP_SSL false Implicit TLS (port 465).
resendApiKey PYXLE_MAIL_RESEND_API_KEY Resend API key (env only).

A misconfigured real provider (e.g. provider: "resend" with no key, or any real provider with no fromAddress) fails loud at startup rather than on the first send.

Example: Resend in production

PYXLE_MAIL_PROVIDER=resend
PYXLE_MAIL_RESEND_API_KEY=re_...
PYXLE_MAIL_FROM=hello@yourdomain.com
PYXLE_MAIL_FROM_NAME="Your App"

Resend requires a verified sender domain (SPF/DKIM DNS records) before it will deliver from anything but its test address.

Sending mail

mail = get_mail_service()

result = await mail.send(
    to=["a@example.com", "b@example.com"],   # str or list
    subject="Monthly digest",
    html="<h1>Hi</h1>",
    text="Hi",                               # at least one of html/text
    reply_to="support@yourdomain.com",
    headers={"List-Unsubscribe": "<https://you/u?t=…>"},   # one-click unsubscribe
)
result.message_id  # provider's id
result.provider    # "console" | "smtp" | "resend" | …

Bad input raises InvalidMessage (no recipient, no body, bad address); a provider rejection or transport failure raises SendError. Both inherit MailError.

What pyxle-mail is not

  • Not a newsletter/campaign system. It sends transactional and one-off mail. Audiences, scheduling, and analytics are out of scope.
  • Not a template engine. Pass rendered HTML/text — use your own templating (Pyxle components, Jinja, f-strings).
  • Not a queue. A send awaits the provider. For high volume or retries, enqueue with a background-jobs plugin and send from the worker.

See also

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

pyxle_mail-0.1.0.tar.gz (18.6 kB view details)

Uploaded Source

Built Distribution

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

pyxle_mail-0.1.0-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

Details for the file pyxle_mail-0.1.0.tar.gz.

File metadata

  • Download URL: pyxle_mail-0.1.0.tar.gz
  • Upload date:
  • Size: 18.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyxle_mail-0.1.0.tar.gz
Algorithm Hash digest
SHA256 09e68bd5a836220a60172f666aaf213f092e6db3003ca846ee11c1e1e5800014
MD5 8314677d50af6e808516303c2c1e1b34
BLAKE2b-256 ba9e70758715d23583cc95b81a63ef97c2d4d34440a43dea85449ec2082cdee1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyxle_mail-0.1.0.tar.gz:

Publisher: publish.yml on pyxle-dev/pyxle-plugins

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

File details

Details for the file pyxle_mail-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyxle_mail-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyxle_mail-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 45b13b115b183942fcbb5a94c85d5e3c02b382a3848ee25f0da5ac024984f718
MD5 fe9923d7c68ac2824802830abe4fa0af
BLAKE2b-256 a06bcc5893b91e7c6301c56f67c10600da8cac42ab181803386df5db80e92ebd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyxle_mail-0.1.0-py3-none-any.whl:

Publisher: publish.yml on pyxle-dev/pyxle-plugins

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