如何使用 Python 中的电子邮件模块从 'application/pkcs7-mime' 中提取数据?
How to extract data from 'application/pkcs7-mime' using the email-module in Python?
问题
我正在做一个我们必须对电子邮件进行分类的项目。对于这个项目,我需要从电子邮件及其附件中提取所有文本。
我的问题是有些附件属于 "application/pkcs7-mime" 类型,我不确定如何处理这些附件。
我试过的
import email, base64
# Opening message
eml_file = '/path/to/file.eml'
message = email.message_from_file(open(eml_file))
# Printing content types
for part in message.walk():
print(part.get_content_type())
>multipart/mixed
text/plain
message/rfc822
application/pkcs7-mime
出问题的部分是"application/pkcs7-mime"。接下来我尝试从有效负载中提取数据。
# Ensuring we got the right payload
message.get_payload(1).get_payload(0).get_content_type()
>application/pkcs7-mime
# Getting payload
message.get_payload(1).get_payload(0).get_payload()
MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwGggxDhqwSD
EOGmQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PV8wMDRfRkVGNjMyNEIy
NDFFNDA5MEFBMUQ3RUQ5QUZBQkZFMDdic2Vka187DQogbWljYWxnPXNoYTI1Ng0KDQotLV8wMDRf
RkVGNjMyNEIyNDFFNDA5MEFBMUQ3RUQ5QUZBQkZFMDdic2Vka18NCkNvbnRlbnQtVHlwZTogdGV4
dC9odG1sOyBjaGFyc2V0PXV0Zi04DQpDb250ZW50LUlEOiA8Mzg3NTg2Nzk0M0UzNkY0OUEzQjcy
.......
有效负载似乎是用 base64 编码的,所以我尝试对其进行解码:
# Decoding message
message.get_payload(1).get_payload(0).get_payload(decode=True).decode("iso-8859-1")
# Top of output
á«á¦Content-Type: multipart/mixed; boundary=_004_FEF6324B241E4090AA1D7ED9AFABFE07bsedk_;
micalg=sha256
--_004_FEF6324B241E4090AA1D7ED9AFABFE07bsedk_
Content-Type: text/html; charset=utf-8
Content-ID: <3875867943E36F49A3B72D0FAEB1DC35@eurprd01.prod.exchangelabs.com>
Content-Transfer-Encoding: base64
PGh0bWwgeG1sbnM6bz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6b2ZmaWNlIiB4
bWxuczp3PSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTp3b3JkIiB4bWxuczptPSJo
dHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS8yMDA0LzEyL29tbWwiIHhtbG5zPSJo
# Bottom of output
0U 0U00, * (&http://crl.oces.trust2408.com/oces.crl0\ Z X¤V0T10 UDK10U
×ÿÑE|g¢¿ºÊ]6¾ãñJfYéÿBû´s²J7ª¡-*¨ Ø p@6¨Ë9ǦíæýÕUB9Íõ £àg&7î!Ö®?sÒ
8Wè>º|mIh +|2¨Ü%«O´|%o¬¦¥ð¶oòÝ¿t³ é¾ÏPÒëqûW®ö8|¼èÇçqQL ½þ¹Ù`¶¿*7ÒýsÎKb!ÿ¶?:{¸½Ú\õ{ÕþyÅI
.éÃÂKèj36q°lD}|RÎàIzÙ/^[j;3¶Ðà+®r$¥!1ß0Û0I0A10 UDK10UªÏÒ¶,`§rÌbèñy5&FJÃ(êí°&¬,ÚêX$á.=ïïæN$®]Þ½yU0+*§ÔÚ´í6azL(!DÏÝ6ÂNê,Ä5FsíXEó§î_»SG]Úüåt Ô¼'âröÓg!ðSÐ,O¶x><s5ÖRv«N¸¡¿<ý>¼VBñ¤f[ÔÏàø7¿ÂûÊ
uidÊUS!ÂÕÜÚæòÜíþµüâeüLü'^[¦/d{«oäp¹ÁNî÷Ž½Oq$Øà-W
DsüèXÀÎ}á¾9À̹ÙÎhAÎ ¯P¾ñäK!VIrÏ̯Ín,º~¿IÐ{[D¢=ý%Úîckr¿·_³EÙ]¨g0âk:`vÄÖ</È»HBà4%ª]|;~wÐ=·&;êºÕAr«Á¡GÅòØ)wÂd{Ù BvÞ·3ºàCÔ
结论
部分消息已正确解码,而其余部分则一团糟。但是,我不知道哪里出了问题。
现在我已经解决了这个问题,方法是编写处理这些文件的方法,从 header 中删除垃圾并将它们转换回消息。这似乎暂时有效。
if message.get_filename() == "smime.p7m":
message = email.message_from_bytes(re.sub(r'.*Content-Type:', 'Content-Type:', decoded).encode("iso-8859-1"))
我遇到了同样的情况,并通过 esben-eickhardt 的回答解决了我的问题。但是我不太高兴为了让它发挥作用而删除一些未知的东西。
Preparation/Reading
RFC 8551 - Secure/Multipurpose Internet 邮件扩展 (S/MIME)
- https://www.rfc-editor.org/rfc/rfc8551
- mime 正文作为 CMS 放入邮件中
RFC 5652 - 加密消息语法 (CMS)
- https://www.rfc-editor.org/rfc/rfc5652
- CMS 使用 ANS.1 数据结构编码
RFC 4792 - 抽象语法符号一 (ASN.1)
使用openssl验证
解压,base64解码p7m文件并调用openssl
openssl asn1parse -in smime.p7m -inform der
这应该神奇地 return CMS 的人类可读结构。您应该将邮件视为 CMS 中的众多键之一。
解决方案
我们需要一个 ASN.1 解析器来读取 CMS 数据。作为第二步,我们提取内部邮件。
Python
Python 包 asn1crypto
是一个 ASN.1 解析器,但也有 CMS 支持。所以现在我们可以将 CMS 加载到 python 表示中。
if part.get_content_type() in ['application/pkcs7-mime'] and part.get_param('smime-type') == 'signed-data':
from asn1crypto import cms
content_info = cms.ContentInfo.load(part.get_payload(decode=True))
compressed_data = content_info['content']
smime = compressed_data['encap_content_info']['content'].native
smime_message = email.message_from_string(smime)
问题
我正在做一个我们必须对电子邮件进行分类的项目。对于这个项目,我需要从电子邮件及其附件中提取所有文本。
我的问题是有些附件属于 "application/pkcs7-mime" 类型,我不确定如何处理这些附件。
我试过的
import email, base64
# Opening message
eml_file = '/path/to/file.eml'
message = email.message_from_file(open(eml_file))
# Printing content types
for part in message.walk():
print(part.get_content_type())
>multipart/mixed
text/plain
message/rfc822
application/pkcs7-mime
出问题的部分是"application/pkcs7-mime"。接下来我尝试从有效负载中提取数据。
# Ensuring we got the right payload
message.get_payload(1).get_payload(0).get_content_type()
>application/pkcs7-mime
# Getting payload
message.get_payload(1).get_payload(0).get_payload()
MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwGggxDhqwSD
EOGmQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PV8wMDRfRkVGNjMyNEIy
NDFFNDA5MEFBMUQ3RUQ5QUZBQkZFMDdic2Vka187DQogbWljYWxnPXNoYTI1Ng0KDQotLV8wMDRf
RkVGNjMyNEIyNDFFNDA5MEFBMUQ3RUQ5QUZBQkZFMDdic2Vka18NCkNvbnRlbnQtVHlwZTogdGV4
dC9odG1sOyBjaGFyc2V0PXV0Zi04DQpDb250ZW50LUlEOiA8Mzg3NTg2Nzk0M0UzNkY0OUEzQjcy
.......
有效负载似乎是用 base64 编码的,所以我尝试对其进行解码:
# Decoding message
message.get_payload(1).get_payload(0).get_payload(decode=True).decode("iso-8859-1")
# Top of output
á«á¦Content-Type: multipart/mixed; boundary=_004_FEF6324B241E4090AA1D7ED9AFABFE07bsedk_;
micalg=sha256
--_004_FEF6324B241E4090AA1D7ED9AFABFE07bsedk_
Content-Type: text/html; charset=utf-8
Content-ID: <3875867943E36F49A3B72D0FAEB1DC35@eurprd01.prod.exchangelabs.com>
Content-Transfer-Encoding: base64
PGh0bWwgeG1sbnM6bz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6b2ZmaWNlIiB4
bWxuczp3PSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTp3b3JkIiB4bWxuczptPSJo
dHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL29mZmljZS8yMDA0LzEyL29tbWwiIHhtbG5zPSJo
# Bottom of output
0U 0U00, * (&http://crl.oces.trust2408.com/oces.crl0\ Z X¤V0T10 UDK10U
×ÿÑE|g¢¿ºÊ]6¾ãñJfYéÿBû´s²J7ª¡-*¨ Ø p@6¨Ë9ǦíæýÕUB9Íõ £àg&7î!Ö®?sÒ
8Wè>º|mIh +|2¨Ü%«O´|%o¬¦¥ð¶oòÝ¿t³ é¾ÏPÒëqûW®ö8|¼èÇçqQL ½þ¹Ù`¶¿*7ÒýsÎKb!ÿ¶?:{¸½Ú\õ{ÕþyÅI
.éÃÂKèj36q°lD}|RÎàIzÙ/^[j;3¶Ðà+®r$¥!1ß0Û0I0A10 UDK10UªÏÒ¶,`§rÌbèñy5&FJÃ(êí°&¬,ÚêX$á.=ïïæN$®]Þ½yU0+*§ÔÚ´í6azL(!DÏÝ6ÂNê,Ä5FsíXEó§î_»SG]Úüåt Ô¼'âröÓg!ðSÐ,O¶x><s5ÖRv«N¸¡¿<ý>¼VBñ¤f[ÔÏàø7¿ÂûÊ
uidÊUS!ÂÕÜÚæòÜíþµüâeüLü'^[¦/d{«oäp¹ÁNî÷Ž½Oq$Øà-W
DsüèXÀÎ}á¾9À̹ÙÎhAÎ ¯P¾ñäK!VIrÏ̯Ín,º~¿IÐ{[D¢=ý%Úîckr¿·_³EÙ]¨g0âk:`vÄÖ</È»HBà4%ª]|;~wÐ=·&;êºÕAr«Á¡GÅòØ)wÂd{Ù BvÞ·3ºàCÔ
结论
部分消息已正确解码,而其余部分则一团糟。但是,我不知道哪里出了问题。
现在我已经解决了这个问题,方法是编写处理这些文件的方法,从 header 中删除垃圾并将它们转换回消息。这似乎暂时有效。
if message.get_filename() == "smime.p7m":
message = email.message_from_bytes(re.sub(r'.*Content-Type:', 'Content-Type:', decoded).encode("iso-8859-1"))
我遇到了同样的情况,并通过 esben-eickhardt 的回答解决了我的问题。但是我不太高兴为了让它发挥作用而删除一些未知的东西。
Preparation/Reading
RFC 8551 - Secure/Multipurpose Internet 邮件扩展 (S/MIME)
- https://www.rfc-editor.org/rfc/rfc8551
- mime 正文作为 CMS 放入邮件中
RFC 5652 - 加密消息语法 (CMS)
- https://www.rfc-editor.org/rfc/rfc5652
- CMS 使用 ANS.1 数据结构编码
RFC 4792 - 抽象语法符号一 (ASN.1)
使用openssl验证
解压,base64解码p7m文件并调用openssl
openssl asn1parse -in smime.p7m -inform der
这应该神奇地 return CMS 的人类可读结构。您应该将邮件视为 CMS 中的众多键之一。
解决方案
我们需要一个 ASN.1 解析器来读取 CMS 数据。作为第二步,我们提取内部邮件。
Python
Python 包 asn1crypto
是一个 ASN.1 解析器,但也有 CMS 支持。所以现在我们可以将 CMS 加载到 python 表示中。
if part.get_content_type() in ['application/pkcs7-mime'] and part.get_param('smime-type') == 'signed-data':
from asn1crypto import cms
content_info = cms.ContentInfo.load(part.get_payload(decode=True))
compressed_data = content_info['content']
smime = compressed_data['encap_content_info']['content'].native
smime_message = email.message_from_string(smime)