diff --git a/gpgmymail b/gpgmymail index 21c46e6..2010fc3 100755 --- a/gpgmymail +++ b/gpgmymail @@ -34,12 +34,16 @@ import email.mime.application import email.mime.multipart import email.mime.message import typing +# for decode_email: +import quopri +import base64 # see: https://gnupg.readthedocs.io/en/latest/ import gnupg # constants 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: """Determines whether or not an email message is encrypted. @@ -55,19 +59,43 @@ def decode_email(message: email.message.Message) -> email.message.Message: :param message: email.message.Message to be decoded :return: decoded email.message.Message""" - if message.is_multipart(): - payload = [] - for part in message.walk(): - if not part.is_multipart(): - payload.append(part.get_payload(decode=True)) + # this is a kinda hacky way to do this by manipulating the message as a + # string but i couldn't get it to work any other way - message.set_payload(payload) - else: - message.set_payload(message.get_payload(decode=True)) + msg_ctes = message.get_all("Content-Transfer-Encoding") + + # 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 - message["Content-Transfer-Encoding"] = "7bit" + # 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) - return message + # 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( message: email.message.Message,