swh.web.inbound_email.utils module#

swh.web.inbound_email.utils.extract_recipients(message: EmailMessage) List[Address][source]#

Extract a list of recipients of the message.

This uses all the fields in HEADERS

class swh.web.inbound_email.utils.AddressMatch(recipient: Address, extension: str | None)[source]#

Bases: object

Data related to a recipient match

recipient: Address#

The original recipient that matched the expected address

extension: str | None#

The parsed +-extension of the matched recipient address

swh.web.inbound_email.utils.single_recipient_matches(recipient: Address, address: str) AddressMatch | None[source]#

Check whether a single address matches the provided base address.

The match is case-insensitive, which is not really RFC-compliant but is consistent with what most people would expect.

This function supports “+-addressing”, where the local part of the email address is appended with a +.

swh.web.inbound_email.utils.recipient_matches(message: EmailMessage, address: str) List[AddressMatch][source]#

Check whether any of the message recipients match the given address.

The match is case-insensitive, which is not really RFC-compliant but matches what most people would expect.

This function supports “+-addressing”, where the local part of the email address is appended with a +.

swh.web.inbound_email.utils.ADDRESS_SIGNER_SEP = '.'#

Separator for email address signatures

swh.web.inbound_email.utils.ADDRESS_SIGNER_DEFAULT = 'sha1'#

Default algorithm for signed address creation

swh.web.inbound_email.utils.ADDRESS_SIGNER_SUPPORTED = ('sha1', 'sha256')#

Supported algorithms for signed address validation

swh.web.inbound_email.utils.get_address_signer(salt: str, algorithm: str = 'sha1', key: str | None = None) Signer[source]#

Get an address signer for the given salt, algorithm and secret key.

swh.web.inbound_email.utils.get_address_for_pk(salt: str, base_address: str, pk: int, algorithm: str = 'sha1', key: str | None = None) str[source]#

Get the email address that will be able to receive messages to be logged in this request.

swh.web.inbound_email.utils.get_pk_from_extension(salt: str, extension: str) int[source]#

Retrieve the primary key for the given inbound address extension.

We reimplement Signer.unsign, because the extension can be casemapped at any point in the email chain (even though email is, theoretically, case sensitive), so we have to compare lowercase versions of both the extension and the signature… We also support addresses generated with multiple signature algorithms, to keep compatibility with older pre-Django 3.1 deployments.

Raises ValueError if the signature couldn’t be verified.

swh.web.inbound_email.utils.get_pks_from_message(salt: str, base_address: str, message: EmailMessage) Set[int][source]#

Retrieve the set of primary keys that were successfully decoded from the recipients of the message matching base_address.

This uses recipient_matches() to retrieve all the recipient addresses matching base_address, then get_pk_from_extension() to decode the primary key and verify the signature for every extension. To generate relevant email addresses, use get_address_for_pk() with the same base_address and salt.

Returns:

the set of primary keys that were successfully decoded from the recipients of the message

swh.web.inbound_email.utils.get_message_plaintext(message: EmailMessage) str | None[source]#

Get the plaintext body for a given message, if any such part exists. If only a html part exists, return that instead.

If there are multiple, ambiguous plain text or html parts in the message, this function will return the largest of them.