mirror of
https://github.com/akissinger/dodo.git
synced 2024-10-04 06:27:25 +03:00
fix error in saving non-ascii headers to file
When a new message was saved after sending, the address headers were not encoded correctly. The complete header was encoded as one encoded word without separating the tokens. For example the header To: émail <émail@example.net>, mail <mail@example.net>\n\n was stored as =?utf-8?b?w6ltYWlsIDzDqW1haWxAZXhhbXBsZS5uZXQ+LCBtYWlsIDxtYWlsQGV4YW1wbGUubmV0Pg==?=\n\n in stead of To: =?utf-8?q?=C3=A9mail?= <=?utf-8?q?=C3=A9mail?=@example.net>, mail <mail@example.net>\n\n This incorrect header ended up in the notmuch database and the message was not found with address queries. The solution also improves utf8 handling by storing all headers and body utf8 encoded (in stead of using 7bit encoding).
This commit is contained in:
parent
2f3fb2b39e
commit
01ba6090de
@ -26,9 +26,8 @@ import mailbox
|
||||
import email
|
||||
import email.utils
|
||||
import email.parser
|
||||
import email.generator
|
||||
import email.policy
|
||||
import mimetypes
|
||||
from io import BytesIO
|
||||
import subprocess
|
||||
from subprocess import PIPE, Popen, TimeoutExpired
|
||||
import tempfile
|
||||
@ -366,22 +365,24 @@ class SendmailThread(QThread):
|
||||
'8': "SHA256", '9': "SHA384", '10': "SHA512",
|
||||
'11': "SHA224"}
|
||||
|
||||
# Generate a copy of the message with <CR><LF> line separators as
|
||||
# required .per rfc-3156
|
||||
# Generate a 7-bit clean copy of the message with <CR><LF> line separators as
|
||||
# required per rfc-3156
|
||||
# Moreover, by working on the copy we leave the original message
|
||||
# (msg) unaltered.
|
||||
gpg_policy = msg.policy.clone(linesep='\r\n')
|
||||
text_to_sign = BytesIO()
|
||||
gen = email.generator.BytesGenerator(text_to_sign, policy=gpg_policy)
|
||||
gen.flatten(msg)
|
||||
text_to_sign.seek(0)
|
||||
msg_to_sign = email.message_from_binary_file(text_to_sign, policy=gpg_policy)
|
||||
text_to_sign.close() # Discard the buffer
|
||||
gpg_policy = msg.policy.clone(linesep='\r\n',utf8=False)
|
||||
msg_to_sign = email.message_from_string(msg.as_string(),policy=gpg_policy)
|
||||
# Create a new mail that will contain the original message and its signature
|
||||
signed_mail = email.message.EmailMessage(policy=msg.policy.clone(linesep='\r\n'))
|
||||
# copy the non Content-* headers to the new mail and remove them form the
|
||||
# message that will be signed
|
||||
for k, v in msg.items():
|
||||
if not k.lower().startswith('content-'):
|
||||
signed_mail[k] = v
|
||||
|
||||
# Create a new message that will contain the original message and the
|
||||
# pgp-signature. Move the non Content-* headers to the new message
|
||||
signed_mail = email.message.EmailMessage(policy=gpg_policy)
|
||||
for k, v in msg_to_sign.items():
|
||||
for k, v in msg.items():
|
||||
if not k.lower().startswith('content-'):
|
||||
signed_mail[k] = v
|
||||
del msg_to_sign[k]
|
||||
@ -391,13 +392,14 @@ class SendmailThread(QThread):
|
||||
# Attach the message to be signed
|
||||
signed_mail.attach(msg_to_sign)
|
||||
|
||||
# Create the signature based on attached message
|
||||
# Create the signature
|
||||
gpg = gnupg.GPG(gnupghome=settings.gnupg_home, use_agent=True)
|
||||
sig = gpg.sign(str(signed_mail.get_payload(0)), keyid=settings.gnupg_keyid, detach=True)
|
||||
# Attach the signature to the new message
|
||||
sig = gpg.sign(msg_to_sign.as_string(), keyid=settings.gnupg_keyid, detach=True)
|
||||
# Attach the ASCII representation (as per rfc) of the signature, note that
|
||||
# set_content with contaent-type other then text requires a bytes object
|
||||
sigpart = email.message.EmailMessage()
|
||||
sigpart['Content-Type'] = 'application/pgp-signature'
|
||||
sigpart.set_payload(str(sig))
|
||||
sigpart.set_content(str(sig).encode(), 'application', 'pgp-signature',
|
||||
filename='signature.asc', cte='7bit')
|
||||
signed_mail.attach(sigpart)
|
||||
signed_mail.set_param("micalg", 'pgp-' +
|
||||
RFC4880_HASH_ALGO[sig.hash_algo].lower())
|
||||
@ -407,7 +409,7 @@ class SendmailThread(QThread):
|
||||
try:
|
||||
account = self.panel.account_name()
|
||||
m = email.message_from_string(self.panel.message_string)
|
||||
eml = email.message.EmailMessage()
|
||||
eml = email.message.EmailMessage(policy=email.policy.EmailPolicy(utf8=True))
|
||||
attachments: List[str] = m.get_all('A', [])
|
||||
|
||||
# n.b. this kills duplicate headers. May want to revisit this if it causes problems.
|
||||
@ -468,7 +470,7 @@ class SendmailThread(QThread):
|
||||
sendmail.wait(30)
|
||||
if sendmail.returncode == 0:
|
||||
# save to sent folder
|
||||
m = mailbox.MaildirMessage(str(eml))
|
||||
m = mailbox.MaildirMessage(eml.as_bytes())
|
||||
m.set_flags('S')
|
||||
if isinstance(settings.sent_dir, dict):
|
||||
sent_dir = settings.sent_dir[account]
|
||||
|
Loading…
Reference in New Issue
Block a user