Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated tests #43

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/run-unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", 3.11, 3.12]
python-version: ["3.10", 3.11, 3.12, 3.13]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -15,7 +15,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install M2Crypto
pip install M2Crypto # TODO remove when tests are updated
pip install cryptography
pip install -e .
- name: Run tests
run: python3 test_.py
Expand All @@ -26,12 +27,12 @@ jobs:
run: pip uninstall python-magic -y
- name: Test libmagic missing
id: should_fail
run: python3 tests.py TestMime.test_libmagic
run: python3 test_.py TestMime.test_libmagic
continue-on-error: true
- name: Check on failures
if: steps.should_fail.outcome != 'failure'
run: exit 1
- name: Install file-magic
run: pip install file-magic
- name: Test file-magic
run: python3 test_.py TestMime.test_libmagic
run: python3 test_.py TestMime.test_libmagic
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Envelope

[![Build Status](https://github.com/CZ-NIC/envelope/actions/workflows/run-unittest.yml/badge.svg)](https://github.com/CZ-NIC/envelope/actions) [![Downloads](https://pepy.tech/badge/envelope)](https://pepy.tech/project/envelope)
[![Build Status](https://github.com/CZ-NIC/envelope/actions/workflows/run-unittest.yml/badge.svg)](https://github.com/CZ-NIC/envelope/actions) [![Downloads](https://static.pepy.tech/badge/envelope)](https://pepy.tech/project/envelope)

Quick layer over [python-gnupg](https://bitbucket.org/vinay.sajip/python-gnupg/src), [M2Crypto](https://m2crypto.readthedocs.io/), [smtplib](https://docs.python.org/3/library/smtplib.html), [magic](https://pypi.org/project/python-magic/) and [email](https://docs.python.org/3/library/email.html?highlight=email#module-email) handling packages. Their common use cases merged into a single function. Want to sign a text and tired of forgetting how to do it right? You do not need to know everything about GPG or S/MIME, you do not have to bother with importing keys. Do not hassle with reconnecting to an SMTP server. Do not study various headers meanings to let your users unsubscribe via a URL.
You insert a message, attachments and inline images and receive signed and/or encrypted output to the file or to your recipients' e-mail.
Expand Down Expand Up @@ -77,7 +77,7 @@ Envelope.load(path="message.eml").attachments()
```
* Or just download the project and launch `python3 -m envelope`
* If planning to sign/encrypt with GPG, assure you have it on the system with `sudo apt install gpg` and possibly see [Configure your GPG](#configure-your-gpg) tutorial.
* If planning to use S/MIME, you should ensure some prerequisites: `sudo apt install swig build-essential python3-dev libssl-dev && pip3 install M2Crypto`
* If planning to use S/MIME, you might be required to ensure some [prerequisites](https://cryptography.io/en/latest/installation/), ex: `sudo apt install build-essential libssl-dev libffi-dev python3-dev cargo pkg-config`
* If planning to send e-mails, prepare SMTP credentials or visit [Configure your SMTP](#configure-your-smtp) tutorial.
* If your e-mails are to be received outside your local domain, visit [DMARC](#dmarc) section.
* Package [python-magic](https://pypi.org/project/python-magic/) is used as a dependency. Due to a [well-known](https://github.com/ahupp/python-magic/blob/master/COMPAT.md) name clash with the [file-magic](https://pypi.org/project/file-magic/) package, in case you need to use the latter, don't worry to run `pip uninstall python-magic && pip install file-magic` after installing envelope which is fully compatible with both projects. Both use `libmagic` under the hood which is probably already installed. However, if it is not, [install](https://github.com/ahupp/python-magic?tab=readme-ov-file#installation) `sudo apt install libmagic1`.
Expand Down
32 changes: 30 additions & 2 deletions envelope/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
from os import environ
import re
import sys
from .utils import assure_list

environ['PY3VE_IGNORE_UPDATER'] = '1'
Expand All @@ -11,6 +12,23 @@
logger = logging.getLogger(__name__)


def _getaddresses(*args):
# NOTE Python finally changed the old way of parsing wrong addresses.
# We might start using strict=True (default) in the future.
if sys.version_info <= (3, 11):
return getaddresses(*args)
return getaddresses(*args, strict=False)


def _parseaddr(*args):
# NOTE Python finally changed the old way of parsing wrong addresses.
# We might start using strict=True (default) in the future.
# README should reflect that.
if sys.version_info <= (3, 11):
return parseaddr(*args)
return parseaddr(*args, strict=False)


class Address(str):
"""
You can safely access the `self.name` property to access the real name and `self.address` to access the e-mail address.
Expand All @@ -37,12 +55,14 @@ class Address(str):

def __new__(cls, displayed_email=None, name=None, address=None):
if displayed_email:
v = parseaddr(cls.remedy(displayed_email))
v = _parseaddr(cls.remedy(displayed_email))
name, address = v[0] or name, v[1] or address

if name:
displayed_email = f"{name} <{address}>"
else:
displayed_email = address

instance = super().__new__(cls, displayed_email or "")
instance._name, instance._address = name or "", address or ""
return instance
Expand Down Expand Up @@ -143,7 +163,7 @@ def parse(cls, email_or_list, single=False, allow_false=False):
if allow_false and email_or_list is False:
return False

addrs = getaddresses(cls.remedy(x) for x in assure_list(email_or_list))
addrs = _getaddresses(cls.remedy(x) for x in assure_list(email_or_list))
addresses = [Address(name=real_name, address=address)
for real_name, address in addrs if not (real_name == address == "")]
if single:
Expand All @@ -153,6 +173,8 @@ def parse(cls, email_or_list, single=False, allow_false=False):
return addresses[0]
# if len(addresses) == 0:
# raise ValueError(f"E-mail address cannot be parsed: {email_or_list}")
# if len(addresses) == 0:
# return email_or_list
return addresses

@classmethod
Expand All @@ -162,6 +184,12 @@ def remedy(s):
parsed as two distinguish addresses with getaddresses. Rename the at-sign in the display name
to "person--AT--example.com <person@example2.com>" so that the result of getaddresses is less wrong.
"""

"""
What happens when the string have more addresses?
It also needs to get the address from string like "person@example.com, <person@example.com>" so we need to
take care of the comma and semicolon as well.
"""
if s.group(1).strip() == s.group(2).strip():
# Display name is the same as the e-mail in angle brackets
# Ex: "person@example.com <person@example.com>"
Expand Down
2 changes: 1 addition & 1 deletion envelope/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
except ImportError:
gnupg = None

smime_import_error = "Cannot import M2Crypto. Run: `sudo apt install swig && pip3 install M2Crypto`"
smime_import_error = "Cannot import cryptography. Run: `sudo apt install cryptography`"
CRLF = '\r\n'
AUTO = "auto"
PLAIN = "plain" # XX allow text/plain too?
Expand Down
Loading