PGP-signing multipart e-mails with Python
The problem is that Python's email.generator
module doesn't add a newline before the signature part. I've reported that upstream as http://bugs.python.org/issue14983.
(The bug was fixed in Python2.7 and 3.3+ in 2014)
What is actually the MIME structure of basemsg
? It appears that it has too many nested parts in it. If you export a signed message from e.g. Evolution, you'll see that it has just two parts: the body and the signature.
Here's an example which generates a message on stdout that can be read and the signature verified on both mutt (mutt -f test.mbox
) and Evolution (File -> Import).
import gnupg
from email.message import Message
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
body = """
This is the original message text.
:)
"""
gpg_passphrase = "xxxx"
basemsg = MIMEText(body)
def messageFromSignature(signature):
message = Message()
message['Content-Type'] = 'application/pgp-signature; name="signature.asc"'
message['Content-Description'] = 'OpenPGP digital signature'
message.set_payload(signature)
return message
gpg = gnupg.GPG()
basetext = basemsg.as_string().replace('\n', '\r\n')
signature = str(gpg.sign(basetext, detach=True, passphrase=gpg_passphrase))
if signature:
signmsg = messageFromSignature(signature)
msg = MIMEMultipart(_subtype="signed", micalg="pgp-sha1",
protocol="application/pgp-signature")
msg.attach(basemsg)
msg.attach(signmsg)
msg['Subject'] = "Test message"
msg['From'] = "[email protected]"
msg['To'] = "[email protected]"
print(msg.as_string(unixfrom=True)) # or send
else:
print('Warning: failed to sign the message!')
Note that here, I'm assuming a keyring with a passphrase, but you may not need that.