https://github.com/jwodder/mailbits
Assorted e-mail utility functions
https://github.com/jwodder/mailbits
available-on-pypi content-type e-mail e-mail-address e-mail-comparison e-mail-inspection email emailmessage python recipients
Last synced: 3 months ago
JSON representation
Assorted e-mail utility functions
- Host: GitHub
- URL: https://github.com/jwodder/mailbits
- Owner: jwodder
- License: mit
- Created: 2021-02-28T04:27:34.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2025-01-23T14:39:19.000Z (5 months ago)
- Last Synced: 2025-04-12T20:09:41.316Z (3 months ago)
- Topics: available-on-pypi, content-type, e-mail, e-mail-address, e-mail-comparison, e-mail-inspection, email, emailmessage, python, recipients
- Language: Python
- Homepage:
- Size: 215 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.rst
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
|repostatus| |ci-status| |coverage| |pyversions| |license|
.. |repostatus| image:: https://www.repostatus.org/badges/latest/active.svg
:target: https://www.repostatus.org/#active
:alt: Project Status: Active — The project has reached a stable, usable
state and is being actively developed... |ci-status| image:: https://github.com/jwodder/mailbits/actions/workflows/test.yml/badge.svg
:target: https://github.com/jwodder/mailbits/actions/workflows/test.yml
:alt: CI Status.. |coverage| image:: https://codecov.io/gh/jwodder/mailbits/branch/master/graph/badge.svg
:target: https://codecov.io/gh/jwodder/mailbits.. |pyversions| image:: https://img.shields.io/pypi/pyversions/mailbits.svg
:target: https://pypi.org/project/mailbits/.. |license| image:: https://img.shields.io/github/license/jwodder/mailbits.svg
:target: https://opensource.org/licenses/MIT
:alt: MIT License`GitHub `_
| `PyPI `_
| `Issues `_
| `Changelog `_``mailbits`` provides a small assortment of functions for working with the
Python standard library's ``Message``/``EmailMessage``, ``Address``, and
``Group`` types, as well as a couple other features. It can parse & reassemble
Content-Type strings, convert instances of the old ``Message`` class to the new
``EmailMessage``, convert ``Message`` & ``EmailMessage`` instances into
structured ``dict``\s, parse addresses, format address lists, and extract
recipients' raw e-mail addresses from an ``EmailMessage``.Installation
============
``mailbits`` requires Python 3.8 or higher. Just use `pip
`_ for Python 3 (You have pip, right?) to install it::python3 -m pip install mailbits
API
===``ContentType``
---------------The ``ContentType`` class provides a representation of a parsed Content-Type
header value. Parse Content-Type strings with the ``parse()`` classmethod,
inspect the parts via the ``content_type``, ``maintype``, ``subtype``, and
``params`` attributes (the last three of which can be mutated), convert back to
a string with ``str()``, and convert to ASCII bytes using encoded words for
non-ASCII with ``bytes()``.>>> from mailbits import ContentType
>>> ct = ContentType.parse("text/plain; charset=utf-8; name*=utf-8''r%C3%A9sum%C3%A9.txt")
>>> ct
ContentType(maintype='text', subtype='plain', params={'charset': 'utf-8', 'name': 'résumé.txt'})
>>> ct.content_type
'text/plain'
>>> ct.maintype
'text'
>>> ct.subtype
'plain'
>>> ct.params
{'charset': 'utf-8', 'name': 'résumé.txt'}
>>> str(ct)
'text/plain; charset="utf-8"; name="résumé.txt"'
>>> bytes(ct)
b'text/plain; charset="utf-8"; name*=utf-8\'\'r%C3%A9sum%C3%A9.txt'``email2dict()``
----------------.. code:: python
class MessageDict(TypedDict):
unixfrom: Optional[str]
headers: Dict[str, Any]
preamble: Optional[str]
content: Any
epilogue: Optional[str]mailbits.email2dict(msg: email.message.Message, include_all: bool = False) -> MessageDict
Convert a ``Message`` object to a ``dict``. All encoded text & bytes are
decoded into their natural values.Need to examine a ``Message`` but find the builtin Python API too fiddly? Need
to check that a ``Message`` has the content & structure you expect? Need to
compare two ``Message`` instances for equality? Need to pretty-print the
structure of a ``Message``? Then ``email2dict()`` has your back.By default, any information specific to how the message is encoded (Content-Type
parameters, Content-Transfer-Encoding, etc.) is not reported, as the focus is
on the actual content rather than the choices made in representing it. To
include this information anyway, set ``include_all`` to ``True``.The output structure has the following fields:
``unixfrom``
The "From " line marking the start of the message in a mbox, if any``headers``
A ``dict`` mapping lowercased header field names to values. The following
headers have special representations:``subject``
A single string``from``, ``to``, ``cc``, ``bcc``, ``resent-from``, ``resent-to``, ``resent-cc``, ``resent-bcc``, ``reply-to``
A list of groups and/or addresses. Addresses are represented as
``dict``\s with two string fields: ``display_name`` (an empty string if
not given) and ``address``. Groups are represented as ``dict``\s with
a ``group`` field giving the name of the group and an ``addresses``
field giving a list of addresses in the group.``message-id``
A single string``content-type``
A ``dict`` containing a ``content_type`` field (a string of the form
``maintype/subtype``, e.g., ``"text/plain"``) and a ``params`` field (a
``dict`` of string keys & values). The ``charset`` and ``boundary``
parameters are discarded unless ``include_all`` is ``True``.``date``
A ``datetime.datetime`` instance``orig-date``
A ``datetime.datetime`` instance``resent-date``
A list of ``datetime.datetime`` instances``sender``
A single address ``dict````resent-sender``
A list of address ``dict``\s``content-disposition``
A ``dict`` containing a ``disposition`` field (value either
``"inline"`` or ``"attachment"``) and a ``params`` field (a ``dict`` of
string keys & values)``content-transfer-encoding``
A single string. This header is discarded unless ``include_all`` is
``True``.``mime-version``
A single string. This header is discarded unless ``include_all`` is
``True``.All other headers are represented as lists of strings.
``preamble``
The message's preamble____ https://docs.python.org/3/library/email.message.html
#email.message.EmailMessage.preamble``content``
If the message is multipart, this is a list of message ``dict``\s,
structured the same way as the top-level ``dict``. If the message's
Content-Type is ``message/rfc822`` or ``message/external-body``, this is a
single message ``dict``. If the message's Content-Type is ``text/*``, this
is a ``str`` giving the contents of the message. Otherwise, it is a
``bytes`` giving the contents of the message.``epilogue``
The message's epilogue____ https://docs.python.org/3/library/email.message.html
#email.message.EmailMessage.epilogueAn example: The ``email`` `examples page`__ in the Python docs includes an
example of constructing an HTML e-mail with an alternative plain text version
(It's the one with the subject "Ayons asperges pour le déjeuner"). Passing the
resulting ``EmailMessage`` object to ``email2dict()`` produces the following
output structure:__ https://docs.python.org/3/library/email.examples.html
.. code:: python
{
"unixfrom": None,
"headers": {
"subject": "Ayons asperges pour le déjeuner",
"from": [
{
"display_name": "Pepé Le Pew",
"address": "[email protected]",
},
],
"to": [
{
"display_name": "Penelope Pussycat",
"address": "[email protected]",
},
{
"display_name": "Fabrette Pussycat",
"address": "[email protected]",
},
],
"content-type": {
"content_type": "multipart/alternative",
"params": {},
},
},
"preamble": None,
"content": [
{
"unixfrom": None,
"headers": {
"content-type": {
"content_type": "text/plain",
"params": {},
},
},
"preamble": None,
"content": (
"Salut!\n"
"\n"
"Cela ressemble à un excellent recipie[1] déjeuner.\n"
"\n"
"[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718\n"
"\n"
"--Pepé\n"
),
"epilogue": None,
},
{
"unixfrom": None,
"headers": {
"content-type": {
"content_type": "multipart/related",
"params": {},
},
},
"preamble": None,
"content": [
{
"unixfrom": None,
"headers": {
"content-type": {
"content_type": "text/html",
"params": {},
},
},
"preamble": None,
"content": (
"\n"
" \n"
" \n"
"Salut!
\n"
"Cela ressemble à un excellent\n"
\n"
" \n"
" recipie\n"
" déjeuner.\n"
"
"\n"
" \n"
"\n"
),
"epilogue": None,
},
{
"unixfrom": None,
"headers": {
"content-type": {
"content_type": "image/png",
"params": {},
},
"content-disposition": {
"disposition": "inline",
"params": {},
},
"content-id": [""],
},
"preamble": None,
"content": b'IMAGE BLOB',
"epilogue": None,
},
],
"epilogue": None,
},
],
"epilogue": None,
}``format_addresses()``
----------------------.. code:: python
mailbits.format_addresses(addresses: Iterable[Union[str, Address, Group]], encode: bool = False) -> str
Convert an iterable of e-mail address strings (of the form
"``[email protected]``", without angle brackets or a display name),
``email.headerregistry.Address`` objects, and/or ``email.headerregistry.Group``
objects into a formatted string. If ``encode`` is ``False`` (the default),
non-ASCII characters are left as-is. If it is ``True``, non-ASCII display
names are converted into :RFC:`2047` encoded words, and non-ASCII domain names
are encoded using Punycode.``message2email()``
-------------------.. code:: python
mailbits.message2email(msg: email.message.Message) -> email.message.EmailMessage
Convert an instance of the old ``Message`` class (or one of its subclasses,
like a ``mailbox`` message class) to an instance of the new ``EmailMessage``
class with the ``default`` policy. If ``msg`` is already an ``EmailMessage``,
it is returned unchanged.``parse_address()``
-------------------.. code:: python
mailbits.parse_address(s: str) -> email.headerregistry.Address
Parse a single e-mail address — either a raw address like "``[email protected]``"
or a combined display name & address like "``Fabian Oh ``"
into an ``Address`` object.``parse_addresses()``
---------------------.. code:: python
mailbits.parse_addresses(s: Union[str, email.headerregistry.AddressHeader]) \
-> List[Union[email.headerregistry.Address, email.headerregistry.Group]]Parse a formatted list of e-mail addresses or the contents of an
``EmailMessage``'s "To", "CC", "BCC", etc. header into a list of ``Address``
and/or ``Group`` objects.``recipient_addresses()``
-------------------------.. code:: python
mailbits.recipient_addresses(msg: email.message.EmailMessage) -> List[str]
Return a sorted list of all of the distinct e-mail addresses (not including
display names) in an ``EmailMessage``'s combined "To", "CC", and "BCC" headers.