如何使用 Python 在现有的 eml 文件中添加 pdf 附件?
How to add pdf attachment in an existing eml file using Python?
目前我正在处理 eml 文件,我最近正在处理这些类型的文件:
我不得不更改发件人姓名并将相同的 eml 文件发送给那些发件人,但我想将 .eml 文件添加到我现有的
我已经通过 email.parser 库使用替换 header 命令成功更改了发件人。
例如:
from email.parser import Parser
f = open('C:\Users\Downloads\Message.eml', 'r+')
header = Parser().parse(f)
headers.replace_header(headername, headervalue)
headers.replace_header('to', 'name@gmail.com')
但现在我不知道如何在同一 .eml 文件的电子邮件 body 中添加 pdf 附件。以下是 .eml 文件的示例。在此我想添加一个附件。
你们能帮忙吗?
.eml 文件模板:
Delivered-To: ***@gmail.com
Received: by 2002:ac9:1e03:0:0:0:0:0 with SMTP id r3csp1380999oci;
Thu, 6 May 2021 03:24:14 -0700 (PDT)
X-Google-Smtp-Source: ABdhPJxznI2eQK4UcAUk1vJbeKdYMovRwYMwxz4trgXWy7O+V1jklccpi92jvFWplswmqnBJfdpV
X-Received: by 2002:a17:2:94:b9:ec:7fd5:193e with SMTP id w4-20020a1709029a84b02900ec7fd5193emr3638953plp.62.1620296654743;
Thu, 06 May 2021 03:24:14 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1620296654; cv=none;
d=google.com; s=arc-20160816;
b=EH7EGZH8A3o9/LvvqIgO3KaZPU82Jn0iX0/kGV5W/tawujBF7y3qV3Er4lpFtX
rm1jiy+cH3CPEHEiAyyd3XSuBZFA+AoE8xpoZxXaTxmqB6vBQXVWigVUUTKcsl71CSVs
xLG7NHWsFABWEdemJY/cnibY85tpk1NpVISzDihAd4IShMKOGlYqoOlyWf06pdyIc2y6
DZVYrlo/oWsnD2VT5nYiVqMeOwjUKIVg9ACyZIIRpmMQT/2/lutcsrLPMBBJbLK1vpgU
jpZHu3s++EFPjmuTijNbyvv/5d5RrcsOwvLpWqk
8U1A==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=from:subject:sender:message-id:to:mime-version:date:dkim-signature;
bh=oz3nVaiXvPhENQytolVf3ACAgfI2p8aslAq1BN/w55M=;
b=fUeNvuOk3JjseXNpa+wFWtdmRjgG/Le5G62cV0ZMbelccGKi1H7GWx
Exred4q9phvSSGV7ZuE+U5MXpwL1tXmPYZhHO+fj5uPEt6dY2x
Yqg2/1IxDhcd/3NLH8CB19AolyRgAA8Qn+ThyBgpHs8mCVQ0f5XzxZvP/rKf
WXxyQwA/1CcOPEcDlaOPAZNngacjvxeecjWWLrHUK1eH
bETcDxabCPKXagRnP4xDXwTSqzj4Gtjsbc7 +v
WGfw==
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@mail.com header.s=mail header.b=LRDuMb9q;
spf=pass (google.com: domain of ***@mail.com designates ****.137.**.*** as permitted sender) smtp.mailfrom=***@mail.com;
dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=mail.com
Return-Path: <***@mail.com>
Received: from mail.com (f4mail-235-203. mail.com. [***.137.**.***])
by mx.google.com with ESMTPS id l10si2328115pgb.331.2021.05.06.03.24.13
for <xxxxx@gmail.com>
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Thu, 06 May 2021 03:24:14 -0700 (PDT)
Received-SPF: pass (google.com: domain of ***@mail.com designates ***.137.**.*** as permitted sender) client-ip=***.137.**.***;
Authentication-Results: mx.google.com;
dkim=pass header.i=@mail.com header.s=mail header.b=LRDuMb9q;
spf=pass (google.com: domain of ***@mail.com designates ***.137.**.*** as permitted sender) smtp.mailfrom=***@mail.com;
dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=mail.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mail.com;
s=mail; t=1620296652;
bh=oz3nVaiXvPhENQytolVf3ACAgfI2p8aslAq1BN/w55M=;
h=MIME-Version:From:Date:Message-ID:Subject:To:Content-Type;
b=LRDuMb9qOWYq/u397M6T9zLkk1kInTolxD538xl5crHBsb3PL8eR5GiE0Deg7fTNe
T8+whLVLTServKQLpxrEE3ob/6c5gr11SFYP8dIyzYU+qhbtxp6OJcAnBuxkJSRgRD
JFQ/6oaHO49Jhz/2qkQ82USjrCi1fiAZe/mBKUGY=
Received: (qmail 20965 invoked by uid 510); 6 May 2021 10:24:12 -0000
x-m-msg: asd54ad564ad7aa6sd5as6d5; a6da7d6asas6dasd77; 5dad65ad5sd;
X-OUT-VDRT-SpamState: 0\LEGIT
X-OUT-VDRT-SpamScore: 0
X-OUT-VDRT-SpamCause: gggruggvucftvghtrhhoucdtuddrgeduledrvdegtddgvdejucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecufdftgfffkffhhfdpqfgfvfdfnecuuegrihhlohhuthemuceftddtnecunecujfgurhepffggvffkshfuhfgtsegrtderredttdejnecuhfhrohhmpedfrfhrihihrghnkhgrucffvghsrghifdcuoehpihihrgguvghsrghiudduuddusehrvgguihhffhhmrghilhdrtghomheqnecuggftrfgrthhtvghrnheptdefkeehkeduhfeljeelleehgefgffeutdeljedtiedtgeeigfdtjeettedvkedtnecukfhppedurddukeeirdduvdegrdduheeinecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmohguvgepshhmthhpohhuth
X-Remote-IP: ***.137.**.***
X-REDF-OSEN: ***@mail.com
Date: 6 May 2021 10:24:12 -0000
MIME-Version: 1.0
To: "***" <***@gmail.com>
Received: from unknown ***.137.**.*** by mail.com via HTTP; 06 May 2021 10:24:12 -0000
X-Senderscore: D=0&S=0
Message-ID: <1620296512.S.1386.3658.f4mail-***-13*.mail.com.1620296652.20941@webmail.mail.com>
Sender: ***@mail.com
Subject: =?utf-8?B?UmVxdWVzdGVkIGRvY3VtZW50cw==?=
From: "Fisrtname Lastname" <***@mail.com>
Content-Type: multipart/alternative;
boundary="=_f619e79a5c2c1319e417d1bc96f343f8"
--=_f619e79a5c2c1319e417d1bc96f343f8
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="UTF-8"
Hey Name,
I hope you are fine and staying safe.
Please find the attached document of some details for the whole process for this program. Once you go through it if you find interest to know then let's have a discussion.
Regards,
Name LastName
--=_f619e79a5c2c1319e417d1bc96f343f8
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="UTF-8"
<br /><br />Hey Name,<br /><br />I hope you are fine and staying safe.<br /=
> <div>Please find the attached document of some details for the whole=
process for this program. Once you go through it if you find interes=
t to know then let's have a discussion.<br /><br />Regards,<br />Name L=
astName<br /> </div><br>
--=_f619e79a5c2c1319e417d1bc96f343f8--
您使用的是旧版 email.message.Message
API,它不容易让您将附件添加到已解析的邮件中。但切换到现代 Python 3.6+ API 很容易,总体上是个好主意,这使它成为 breeze.
有点晦涩,使 email.parser
模块生成现代 EmailMessage
object 而不是遗留 Message
的方法是传入 policy
参数.
顺便说一句,如果电子邮件在磁盘上不是纯 UTF-8,您应该将文件读取为 bytes
并使用 BytesParser
以避免出现奇怪的编码错误。许多 real-world 邮件包含 Latin-1 或各种亚洲字符集;但正确的解决方案是甚至不要尝试猜测 - 只需将其作为二进制 blob 读入并让 email
解析器计算出来。
from email.parser import BytesParser
from email.policy import default
headername = 'sender'
headervalue = 'you need to show us your variables <failure@example.net>'
with open(r'C:\Users\Sun\Download\Message.eml', 'rb') as mess:
message = BytesParser(policy=default).parse(mess)
message.replace_header(headername, headervalue)
message.replace_header('to', 'name@gmail.com')
message.add_attachment(b'\x00\x00\x00', 'attachment', 'pdf', filename='poop.pdf')
add_attachment
方法的文档也有点少;它的参数是附件 body 数据、主要类型和子类型(尽管您可以添加其他参数,例如配置,以便为收件人提供文件名)。参见例如Addng attachment to an EmailMessage raises TypeError: set_text_content() got an unexpected keyword argument 'maintype'
通常,您可能还想从文件中读取 PDF:
from pathlib import Path
pdf_file = Path(r'C:\windows\horrible\atrocious\nasty\file.pdf')
with pdf_file.open('rb') as pdf:
message.add_attachment(
pdf.read(), 'attachment', 'pdf', filename=pdf_file.name)
注意我们如何再次需要二进制输入,以及 message.add_attachment
的第一个参数是如何包含有效负载的 bytes
object。
这里的pathlib
转换并不是绝对必要的,而是展示了如何只输入一次文件名,并将其传递给add_attachment
的filename
关键字参数以使用那里有相同的文件名,没有目录部分。
如果要将修改后的消息写入同一个文件,只需 close
文件句柄(或者更好,在最初读取时使用 with open() ...:
,这样您就不必记住明确地close()
,就像我上面做的那样)并打开阅读,然后写出新内容。再次提醒,记得用二进制方式,写出bytes
.
with open(filename, 'wb') as destination:
destination.write(message.as_bytes())
模糊改编的演示:https://ideone.com/NBMOs1
顺便说一句,您的 SMTP 服务器不关心 To:
header 中的内容;如果你 sendmail me@example.org <Message.eml
它将交付给我,而不是 To:
header 中的任何人。 (sendmail
并不常安装在 Windows 上,但同样的原则也适用。)如果你担心的话,也许你实际上并不想要或不需要更换 To:
header .
目前我正在处理 eml 文件,我最近正在处理这些类型的文件:
我不得不更改发件人姓名并将相同的 eml 文件发送给那些发件人,但我想将 .eml 文件添加到我现有的
我已经通过 email.parser 库使用替换 header 命令成功更改了发件人。
例如:
from email.parser import Parser
f = open('C:\Users\Downloads\Message.eml', 'r+')
header = Parser().parse(f)
headers.replace_header(headername, headervalue)
headers.replace_header('to', 'name@gmail.com')
但现在我不知道如何在同一 .eml 文件的电子邮件 body 中添加 pdf 附件。以下是 .eml 文件的示例。在此我想添加一个附件。
你们能帮忙吗?
.eml 文件模板:
Delivered-To: ***@gmail.com
Received: by 2002:ac9:1e03:0:0:0:0:0 with SMTP id r3csp1380999oci;
Thu, 6 May 2021 03:24:14 -0700 (PDT)
X-Google-Smtp-Source: ABdhPJxznI2eQK4UcAUk1vJbeKdYMovRwYMwxz4trgXWy7O+V1jklccpi92jvFWplswmqnBJfdpV
X-Received: by 2002:a17:2:94:b9:ec:7fd5:193e with SMTP id w4-20020a1709029a84b02900ec7fd5193emr3638953plp.62.1620296654743;
Thu, 06 May 2021 03:24:14 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1620296654; cv=none;
d=google.com; s=arc-20160816;
b=EH7EGZH8A3o9/LvvqIgO3KaZPU82Jn0iX0/kGV5W/tawujBF7y3qV3Er4lpFtX
rm1jiy+cH3CPEHEiAyyd3XSuBZFA+AoE8xpoZxXaTxmqB6vBQXVWigVUUTKcsl71CSVs
xLG7NHWsFABWEdemJY/cnibY85tpk1NpVISzDihAd4IShMKOGlYqoOlyWf06pdyIc2y6
DZVYrlo/oWsnD2VT5nYiVqMeOwjUKIVg9ACyZIIRpmMQT/2/lutcsrLPMBBJbLK1vpgU
jpZHu3s++EFPjmuTijNbyvv/5d5RrcsOwvLpWqk
8U1A==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=from:subject:sender:message-id:to:mime-version:date:dkim-signature;
bh=oz3nVaiXvPhENQytolVf3ACAgfI2p8aslAq1BN/w55M=;
b=fUeNvuOk3JjseXNpa+wFWtdmRjgG/Le5G62cV0ZMbelccGKi1H7GWx
Exred4q9phvSSGV7ZuE+U5MXpwL1tXmPYZhHO+fj5uPEt6dY2x
Yqg2/1IxDhcd/3NLH8CB19AolyRgAA8Qn+ThyBgpHs8mCVQ0f5XzxZvP/rKf
WXxyQwA/1CcOPEcDlaOPAZNngacjvxeecjWWLrHUK1eH
bETcDxabCPKXagRnP4xDXwTSqzj4Gtjsbc7 +v
WGfw==
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@mail.com header.s=mail header.b=LRDuMb9q;
spf=pass (google.com: domain of ***@mail.com designates ****.137.**.*** as permitted sender) smtp.mailfrom=***@mail.com;
dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=mail.com
Return-Path: <***@mail.com>
Received: from mail.com (f4mail-235-203. mail.com. [***.137.**.***])
by mx.google.com with ESMTPS id l10si2328115pgb.331.2021.05.06.03.24.13
for <xxxxx@gmail.com>
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Thu, 06 May 2021 03:24:14 -0700 (PDT)
Received-SPF: pass (google.com: domain of ***@mail.com designates ***.137.**.*** as permitted sender) client-ip=***.137.**.***;
Authentication-Results: mx.google.com;
dkim=pass header.i=@mail.com header.s=mail header.b=LRDuMb9q;
spf=pass (google.com: domain of ***@mail.com designates ***.137.**.*** as permitted sender) smtp.mailfrom=***@mail.com;
dmarc=pass (p=QUARANTINE sp=REJECT dis=NONE) header.from=mail.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mail.com;
s=mail; t=1620296652;
bh=oz3nVaiXvPhENQytolVf3ACAgfI2p8aslAq1BN/w55M=;
h=MIME-Version:From:Date:Message-ID:Subject:To:Content-Type;
b=LRDuMb9qOWYq/u397M6T9zLkk1kInTolxD538xl5crHBsb3PL8eR5GiE0Deg7fTNe
T8+whLVLTServKQLpxrEE3ob/6c5gr11SFYP8dIyzYU+qhbtxp6OJcAnBuxkJSRgRD
JFQ/6oaHO49Jhz/2qkQ82USjrCi1fiAZe/mBKUGY=
Received: (qmail 20965 invoked by uid 510); 6 May 2021 10:24:12 -0000
x-m-msg: asd54ad564ad7aa6sd5as6d5; a6da7d6asas6dasd77; 5dad65ad5sd;
X-OUT-VDRT-SpamState: 0\LEGIT
X-OUT-VDRT-SpamScore: 0
X-OUT-VDRT-SpamCause: gggruggvucftvghtrhhoucdtuddrgeduledrvdegtddgvdejucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecufdftgfffkffhhfdpqfgfvfdfnecuuegrihhlohhuthemuceftddtnecunecujfgurhepffggvffkshfuhfgtsegrtderredttdejnecuhfhrohhmpedfrfhrihihrghnkhgrucffvghsrghifdcuoehpihihrgguvghsrghiudduuddusehrvgguihhffhhmrghilhdrtghomheqnecuggftrfgrthhtvghrnheptdefkeehkeduhfeljeelleehgefgffeutdeljedtiedtgeeigfdtjeettedvkedtnecukfhppedurddukeeirdduvdegrdduheeinecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmohguvgepshhmthhpohhuth
X-Remote-IP: ***.137.**.***
X-REDF-OSEN: ***@mail.com
Date: 6 May 2021 10:24:12 -0000
MIME-Version: 1.0
To: "***" <***@gmail.com>
Received: from unknown ***.137.**.*** by mail.com via HTTP; 06 May 2021 10:24:12 -0000
X-Senderscore: D=0&S=0
Message-ID: <1620296512.S.1386.3658.f4mail-***-13*.mail.com.1620296652.20941@webmail.mail.com>
Sender: ***@mail.com
Subject: =?utf-8?B?UmVxdWVzdGVkIGRvY3VtZW50cw==?=
From: "Fisrtname Lastname" <***@mail.com>
Content-Type: multipart/alternative;
boundary="=_f619e79a5c2c1319e417d1bc96f343f8"
--=_f619e79a5c2c1319e417d1bc96f343f8
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="UTF-8"
Hey Name,
I hope you are fine and staying safe.
Please find the attached document of some details for the whole process for this program. Once you go through it if you find interest to know then let's have a discussion.
Regards,
Name LastName
--=_f619e79a5c2c1319e417d1bc96f343f8
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="UTF-8"
<br /><br />Hey Name,<br /><br />I hope you are fine and staying safe.<br /=
> <div>Please find the attached document of some details for the whole=
process for this program. Once you go through it if you find interes=
t to know then let's have a discussion.<br /><br />Regards,<br />Name L=
astName<br /> </div><br>
--=_f619e79a5c2c1319e417d1bc96f343f8--
您使用的是旧版 email.message.Message
API,它不容易让您将附件添加到已解析的邮件中。但切换到现代 Python 3.6+ API 很容易,总体上是个好主意,这使它成为 breeze.
有点晦涩,使 email.parser
模块生成现代 EmailMessage
object 而不是遗留 Message
的方法是传入 policy
参数.
顺便说一句,如果电子邮件在磁盘上不是纯 UTF-8,您应该将文件读取为 bytes
并使用 BytesParser
以避免出现奇怪的编码错误。许多 real-world 邮件包含 Latin-1 或各种亚洲字符集;但正确的解决方案是甚至不要尝试猜测 - 只需将其作为二进制 blob 读入并让 email
解析器计算出来。
from email.parser import BytesParser
from email.policy import default
headername = 'sender'
headervalue = 'you need to show us your variables <failure@example.net>'
with open(r'C:\Users\Sun\Download\Message.eml', 'rb') as mess:
message = BytesParser(policy=default).parse(mess)
message.replace_header(headername, headervalue)
message.replace_header('to', 'name@gmail.com')
message.add_attachment(b'\x00\x00\x00', 'attachment', 'pdf', filename='poop.pdf')
add_attachment
方法的文档也有点少;它的参数是附件 body 数据、主要类型和子类型(尽管您可以添加其他参数,例如配置,以便为收件人提供文件名)。参见例如Addng attachment to an EmailMessage raises TypeError: set_text_content() got an unexpected keyword argument 'maintype'
通常,您可能还想从文件中读取 PDF:
from pathlib import Path
pdf_file = Path(r'C:\windows\horrible\atrocious\nasty\file.pdf')
with pdf_file.open('rb') as pdf:
message.add_attachment(
pdf.read(), 'attachment', 'pdf', filename=pdf_file.name)
注意我们如何再次需要二进制输入,以及 message.add_attachment
的第一个参数是如何包含有效负载的 bytes
object。
这里的pathlib
转换并不是绝对必要的,而是展示了如何只输入一次文件名,并将其传递给add_attachment
的filename
关键字参数以使用那里有相同的文件名,没有目录部分。
如果要将修改后的消息写入同一个文件,只需 close
文件句柄(或者更好,在最初读取时使用 with open() ...:
,这样您就不必记住明确地close()
,就像我上面做的那样)并打开阅读,然后写出新内容。再次提醒,记得用二进制方式,写出bytes
.
with open(filename, 'wb') as destination:
destination.write(message.as_bytes())
模糊改编的演示:https://ideone.com/NBMOs1
顺便说一句,您的 SMTP 服务器不关心 To:
header 中的内容;如果你 sendmail me@example.org <Message.eml
它将交付给我,而不是 To:
header 中的任何人。 (sendmail
并不常安装在 Windows 上,但同样的原则也适用。)如果你担心的话,也许你实际上并不想要或不需要更换 To:
header .