Skip to main content

Make sending emails a bit easier in Python

Project description

iposi

"iposi" is the word for "post" or "post office" in isiXhosa, one of South Africa's twelve official languages. It reflects what this package is for: making sending simple emails with Python a bit simpler.

Installation

pip install iposi

Configuration

You need to provide a few environment variables, so that iposi knows how to communicate with your SMTP server.

Environment variable Required? Description Example
IPOSI_HOST Yes Hostname of the SMTP server. smtp.example.com
IPOSI_PASSWORD No Password for the SMTP server. not_secret
IPOSI_PORT No Port on which the SMTP server is listening. 587
IPOSI_USERNAME No Username for the SMTP server. john.doe
IPOSI_USE_TLS No Whether to use the Transport Layer Security (TLS) protocol. 1

IPOSI_USERNAME and IPOSI_PASSWORD must only be set if the SMTP server supports authentication. If you set either of the two, you must set the other as well.

IPOSI_USE_TLS should be set to 1 if the SMTP server supports TLS, and to 0 otherwise. It is optional; the default value is 1.

If IPOSI_PORT is not set, it is assumed that the SMTP server is listening on port 587.

Usage

Once you have configured all the environment variables, sending emails is as simple as calling mail.

from iposi import mail

mail(
    sender="John Doe <john@example.org>",
    recipients=["Anna Glencore <anna@example.org>", "logging@example.org"],
    subject="Daily Observations",
    plain="Here is the breakdown of the daily observations...",
    html="<p>Here is the breakdown of the daily observations...</p>",
)

The sender must be the address for the email's From field. The recipients must either be a string with a single address or a list of addresses. Only one of plain text or HTML content needs to be supplied.

The mail function sends the email to each recipient individually, i.e. the To field of the email only contains the recipient's address, irrespective of whether there is more than one recipient.

If the email is rejected by the server for a recipient, the function still tries sending it to the remaining recipients. However, after all recipients have been handled it raises a MailError. This error contains a dictionary recipient_errors, whose keys are the failing recipient addresses and whose values are RecipientError instances containing the SMTP code for the failure, the error message and (if available) the exception causing the failure.

The following example shows how you could handle errors when sending an email.

from iposi import mail, MailError

recipients = ["Anna Glencore <anna@example.org>", "logging@example.org", "invalid"]
try:
    mail(
        sender="John Doe <john@example.org>",
        recipients=recipients,
        subject="Daily Observations",
        plain="Here is the breakdown of the daily observations...",
        html="<p>Here is the breakdown of the daily observations...</p>",
    )
except MailError as e:
    print("The email could not be sent to the following recipient(s):")
    for recipient, error in e.recipient_failures.items():
        print()
        print(f"{recipient}:")
        print(f"    SMTP code: {error.smtp_code if error.smtp_code else 'n/a'}")
        print(f"    Message:   {error.message}")

Development and deployment

PDM is used as the package manager for this project. There are several ways to install PDM; one is to use pipx.

pipx install pdm

Also, nox is used as a test runner. It can be installed with pipx.

pipx install nox

Managing dependencies

Use PDM's add command for adding dependencies. For example:

pdm add numpy

To add an optional dependency, use -G/--group <name> option. For example, if you want to add pyjwt to the optional group jwt:

pdm add -G pyjwt

Optional groups are listed in the project.optional-dependencies section of pyproject.toml.

In case the dependency is required for development purposes only, you should use the -dG <name> option. For example, the following will add pytest to the development only group test:

pdm add -dG test pytest

Development only dependency groups are listed in the tool.pdm.dev-dependencies section of pyproject.toml. They `re not included in the published package.

Linting and testing

There are some PDM scripts you can use during development, in addition to PDM's own commands.

Script Description
lint Lint the code. This includes running the precommit and mypy scripts.
test Run the tests.
precommit Run pre-commit on all files.
testcov Run the tests (with coverage).
typecheck Run mypy.

You should run pdm lint and pdm test frequently, ideally before every commit. Before pushing to GitHub, you should run nox (with no arguments); this will run the lint and test PDM scripts, using multiple Python versions for the test one.

Deployment

There is a GitHub workflow (publish.xml) for deploying the package to a package repository (such as PyPI). This workflow assumes that the GitHub repository is a trusted publisher. Refer to the PyPI documentation on how to create a PyPI project with a trusted publisher.

The workflow is triggered whenever a release is created for the GitHub repository. The tag for the release must be the package's version number preceded by a "v". For example, if the package version is "1.4.2", the tag must be "v1.4.2". The tag must be for the current commit in the main branch.

Acknowledgements

The mocking in the unit tests draws heavily on an article in Engineering for Data Science.

Release history

v0.1.0 (26 June 2024)

Initial release

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

iposi-0.1.0.tar.gz (11.3 kB view details)

Uploaded Source

Built Distribution

iposi-0.1.0-py3-none-any.whl (7.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: iposi-0.1.0.tar.gz
  • Upload date:
  • Size: 11.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: pdm/2.16.1 CPython/3.10.12 Linux/6.5.0-1022-azure

File hashes

Hashes for iposi-0.1.0.tar.gz
Algorithm Hash digest
SHA256 002b85d5f6ab1ccc9659845f9151df7724d6181dc6eebc96ac8d56d04ba7e186
MD5 c4ef8f292cdf222acd6a84b993904bb7
BLAKE2b-256 e58f9e83e71bf2792e9eea46c2ba33d4899b13c0686fd2cb06fc09d3a0595bbe

See more details on using hashes here.

File details

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

File metadata

  • Download URL: iposi-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: pdm/2.16.1 CPython/3.10.12 Linux/6.5.0-1022-azure

File hashes

Hashes for iposi-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2080b28def9f0c60ff9d606c6bdfa3c40ad6553ce71720ddc812ee81b537bc27
MD5 d36a1b6389ce6a7d9f9967dab159be48
BLAKE2b-256 ad876238866b2c3e6917929079c3df3a3689c7a06137355c5c4b690fc1a1eea3

See more details on using hashes here.

Supported by

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