7or8bit-decode #5
1 changed files with 38 additions and 10 deletions
48
gpgmymail
48
gpgmymail
|
@ -34,12 +34,16 @@ import email.mime.application
|
||||||
import email.mime.multipart
|
import email.mime.multipart
|
||||||
import email.mime.message
|
import email.mime.message
|
||||||
import typing
|
import typing
|
||||||
|
# for decode_email:
|
||||||
|
import quopri
|
||||||
|
import base64
|
||||||
|
|
||||||
# see: https://gnupg.readthedocs.io/en/latest/
|
# see: https://gnupg.readthedocs.io/en/latest/
|
||||||
import gnupg
|
import gnupg
|
||||||
|
|
||||||
# constants
|
# constants
|
||||||
DEFAULT_ENCODING='utf-8' # default is latin-1 which fails w some unicode chars
|
DEFAULT_ENCODING='utf-8' # default is latin-1 which fails w some unicode chars
|
||||||
|
CTES_TO_BE_DECODED = ("quoted-printable", "base64")
|
||||||
|
|
||||||
def is_message_encrypted(message: email.message.Message) -> bool:
|
def is_message_encrypted(message: email.message.Message) -> bool:
|
||||||
"""Determines whether or not an email message is encrypted.
|
"""Determines whether or not an email message is encrypted.
|
||||||
|
@ -55,20 +59,44 @@ def decode_email(message: email.message.Message) -> email.message.Message:
|
||||||
|
|
||||||
:param message: email.message.Message to be decoded
|
:param message: email.message.Message to be decoded
|
||||||
:return: decoded email.message.Message"""
|
:return: decoded email.message.Message"""
|
||||||
if message.is_multipart():
|
# this is a kinda hacky way to do this by manipulating the message as a
|
||||||
payload = []
|
# string but i couldn't get it to work any other way
|
||||||
for part in message.walk():
|
|
||||||
if not part.is_multipart():
|
|
||||||
payload.append(part.get_payload(decode=True))
|
|
||||||
|
|
||||||
message.set_payload(payload)
|
msg_ctes = message.get_all("Content-Transfer-Encoding")
|
||||||
else:
|
|
||||||
message.set_payload(message.get_payload(decode=True))
|
|
||||||
|
|
||||||
message["Content-Transfer-Encoding"] = "7bit"
|
|
||||||
|
|
||||||
|
# this list will be populated with any encoding that needs to be decoded,
|
||||||
|
# e.g. base64
|
||||||
|
# empty if no decoding needed
|
||||||
|
# set used to avoid dupes
|
||||||
|
decodes_needed = set()
|
||||||
|
# check if any of the parts of the message need decoding
|
||||||
|
for cte in CTES_TO_BE_DECODED:
|
||||||
|
if cte in msg_ctes:
|
||||||
|
decodes_needed.add(cte)
|
||||||
|
# no decoding needed, go ahead with message
|
||||||
|
if not decodes_needed:
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
# decoding needed:
|
||||||
|
# as_string() gives us str, encode() gives us bytes
|
||||||
|
decoded_bytes = msg.as_string().encode()
|
||||||
|
if "quoted-printable" in decodes_needed:
|
||||||
|
decoded_bytes = quopri.decodestring(decoded_bytes)
|
||||||
|
if "base64" in decodes_needed:
|
||||||
|
decoded_bytes = base64.b64decode(decoded_bytes)
|
||||||
|
|
||||||
|
# replace any instances of the Content-Transfer-Encoding header
|
||||||
|
decoded_bytes = decoded_bytes.replace(
|
||||||
|
b'Content-Transfer-Encoding: quoted-printable',
|
||||||
|
b'Content-Transfer-Encoding: 7bit'
|
||||||
|
)
|
||||||
|
decoded_bytes = decoded_bytes.replace(
|
||||||
|
b'Content-Transfer-Encoding: base64',
|
||||||
|
b'Content-Transfer-Encoding: 7bit'
|
||||||
|
)
|
||||||
|
|
||||||
|
return email.message_from_bytes(decoded_bytes)
|
||||||
|
|
||||||
def encrypt(
|
def encrypt(
|
||||||
message: email.message.Message,
|
message: email.message.Message,
|
||||||
recipients: typing.List[str],
|
recipients: typing.List[str],
|
||||||
|
|
Loading…
Reference in a new issue