如何使用Python发送带附件的GPG加密电子邮件

8
我有一个脚本,想要通过电子邮件发送给定文件夹中新生成的文件。我已经能够使用smtplibemailuu生成并发送电子邮件(不加密)。我还成功地发送了一个带有gpg加密但没有附件的电子邮件。
然而,发送带有附件的gpg加密电子邮件是一个挑战。
我使用python-gnupg库创建了一个文件的密文,并认为我可以将其作为电子邮件正文发送。这是我尝试过的方法的大致内容。
from email.mime.text import MIMEText
import gnupg
gpg = gnupg.GPG(gnupghome=GPG_HOME_HOME)
with open(FILE_PATH, "rb") as f:
    cipher_text = str(gpg.encrypt(FILE_PATH.read(), RECIPIENT_EMAIL)

msg = MIMEText(cipher_text, "plain")
msg["Subject"] = "***TEST***"
msg["From"] = EMAIL_SENDER
msg["To"] = EMAIL_RECIPIENT
msg_text = msg.as_string()

我也试着根据我自己的需要调整了 https://docs.python.org/release/3.5.3/library/email-examples.html 的示例,但是也没有成功。

我的gpg已经正确设置,我可以使用thunderbird/enigmail成功地发送/接收gpg加密邮件。

请问有人能告诉我如何发送带附件的gpg加密电子邮件吗? 我相信这需要对电子邮件结构进行一些低级别的操作,但我不太熟悉。

谢谢。


请参考以下链接:使用Python对多部分电子邮件进行PGP签名 - stovfl
2个回答

4

如果你仍然在寻找一个更短的解决方案,可以看看 envelope 库。

pip3 install envelope

它只需要几行代码,就可以处理附件和加密。
from envelope import Envelope

e = (Envelope()
     .message(email_message)
     .from_(EMAIL_FROM)
     .to(email_address_recipient)
     .attach(path=file_path_attachment)
     .encryption())
e.as_message()  # returns EmailMessage
e.smtp("localhost").send()  # directly sends

什么构成加密和解密密钥? - Eric
如果没有明确设置,它将从系统默认密钥环中获取所有提到的联系人的 GPG 密钥 - 在这种情况下,email_address_recipient 的公共(解密)密钥以及 EMAIL_FROM 的私有(加密)和公共(解密)密钥。 - Edvard Rejthar

3

我设法想出了以下方法来实现带附件的gnupg加密邮件的发送。我以使用enigmail发送的thunderbird邮件为模板。

from email.mime.base import MIMEBase
from email.message import Message
import base64
import mimetypes
import os

import gnupg # python-gnupg

def get_email_string(email_address_recipient, file_path_attachment, email_message=""):
    def get_base64_file(file_path):
        with open(file_path, "rb") as f:
            b_str = base64.b64encode(f.read())
        return b_str

    def get_mimetype(file_path):
        return mimetypes.guess_type(file_path)[0]

    def get_file_name(file_path):
        return os.path.basename(file_path)

    def get_gpg_cipher_text(string, recipient_email_address):
        gpg = gnupg.GPG(gnupghome=DIR_GNUPG)
        encrypted_str = str(gpg.encrypt(string, recipient_email_address))
        return encrypted_str


    msg = Message()
    msg.add_header(_name="Content-Type", _value="multipart/mixed", protected_headers="v1")
    msg["From"] = EMAIL_FROM
    msg["To"] = email_address_recipient

    msg_text = Message()
    msg_text.add_header(_name="Content-Type", _value="multipart/mixed")
    msg_text.add_header(_name="Content-Language", _value="en-US")

    msg_body = Message()
    msg_body.add_header(_name="Content-Type", _value="text/plain", charset="utf-8")
    msg_body.add_header(_name="Content-Transfer-Encoding", _value="quoted-printable")
    msg_body.set_payload(email_message + 2*"\n")

    msg_attachment = Message()
    msg_attachment.add_header(_name="Content-Type", _value=get_mimetype(file_path_attachment), name=get_file_name(file_path_attachment))
    msg_attachment.add_header(_name="Content-Transfer-Encoding", _value="base64")
    msg_attachment.add_header(_name="Content-Disposition", _value="attachment", filename=get_file_name(file_path_attachment))
    msg_attachment.set_payload(get_base64_file(file_path_attachment))

    msg_text.attach(msg_body)
    msg_text.attach(msg_attachment)
    msg.attach(msg_text)


    pgp_msg = MIMEBase(_maintype="multipart", _subtype="encrypted", protocol="application/pgp-encrypted")
    pgp_msg["From"] = EMAIL_FROM
    pgp_msg["To"] = email_address_recipient

    pgp_msg_part1 = Message()
    pgp_msg_part1.add_header(_name="Content-Type", _value="application/pgp-encrypted")
    pgp_msg_part1.add_header(_name="Content-Description", _value="PGP/MIME version identification")
    pgp_msg_part1.set_payload("Version: 1" + "\n")

    pgp_msg_part2 = Message()
    pgp_msg_part2.add_header(_name="Content-Type", _value="application/octet-stream", name="encrypted.asc")
    pgp_msg_part2.add_header(_name="Content-Description", _value="OpenPGP encrypted message")
    pgp_msg_part2.add_header(_name="Content-Disposition", _value="inline", filename="encrypted.asc")
    pgp_msg_part2.set_payload(get_gpg_cipher_text(msg.as_string(), email_address_recipient))

    pgp_msg.attach(pgp_msg_part1)
    pgp_msg.attach(pgp_msg_part2)

    return pgp_msg.as_string()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接