有没有一种在事先不知道文件类型的情况下使用 SMTP 在 python 中发送电子邮件附件的快速方法?
Posted
技术标签:
【中文标题】有没有一种在事先不知道文件类型的情况下使用 SMTP 在 python 中发送电子邮件附件的快速方法?【英文标题】:Is there a quick way to send email attachments in python using SMTP without knowing the file type in advance? 【发布时间】:2021-09-12 09:59:17 【问题描述】:我正在开发一个 Python 程序,该程序将使用 SMTP 发送带有附件的电子邮件。到目前为止,通过搜索互联网,我发现了两种将文件附加到 MIME 电子邮件的主要方法。一种方法是使用MIMEBase
类并像这样附加文件(无论文件类型如何):
attach_file = open(attach_file_name, 'rb') # Open the file as binary mode
payload = MIMEBase('application', 'octate-stream')
payload.set_payload((attach_file).read())
encoders.encode_base64(payload) #encode the attachment
attach_file.close()
#add payload header with filename
payload.add_header('Content-Decomposition', "attachment; filename= %s" % attach_file_name)
msg.attach(payload)
这种方法的问题是我发现在许多电子邮件客户端(例如 Gmail)上,附件显示为“noname”并且不可预览(尽管您仍然可以通过下载并使用正确的程序打开来查看它)。
我遇到的第二种方法是附加文件及其类型对应的子类,如下所示:
f=open(attach_file_name, 'rb')
img_data = f.read()
f.close()
image = MIMEImage(img_data, name=os.path.basename(attach_file_name))
msg.attach(image)
此示例适用于图片,并且可以在 Gmail 中正确显示,但不能用于发送其他类型的文件。如果我们想使用方法 2 发送文件,看来我们需要先知道它的类型。有没有一种方法可以轻松确定文件的类型,因为它涉及 MIME,以便代码可以即时执行此操作(无需枚举特定文件类型的所有不同扩展名)?或者有没有办法在不知道其类型的情况下发送附件并使其正确显示?
【问题讨论】:
【参考方案1】:SMTP 不关心附件包含什么。只需将其命名为application/octet-stream
并希望收件人知道如何处理它。但请确保正确拼写 MIME 类型。 (“八位字节”只是“8 位字节”的一种奇特方式。)
另外,Content-Decomposition
不是有效的 MIME 标头名称;你想要Content-Disposition
。
这些可怕的拼写错误可能是您在某些客户端中观察到问题的原因。当您拼错关键技术关键字时,他们无法猜出您的意思。
从根本上说,您的两次尝试似乎都复制/粘贴了几年前的电子邮件代码。当前的 Python 3.6+ email
库代码更具可读性和通用性。可能扔掉你所拥有的,然后重新开始examples in the documentation.
如果您能够正确地猜出您正在传输的文件的 MIME 类型,则将该信息添加到 MIME 标头中会很有用;但对任意附件类型自动执行此操作不太可能有帮助。如果你的猜测逻辑猜错了,你只是在声称你不知道的时候让事情变得更难。
所以,我什至不特别推荐尝试;但是如果您想自己验证这是徒劳的,请尝试mimetypes.guess_type
method from the standard library. 文档建议这仅包含对文件扩展名集合的预设猜测;更彻底的方法是使用文件的实际内容和libmagic
或类似内容来尝试识别它是什么。
【讨论】:
事实上,快速查看mimetypes.py
的源代码可以确认它只是读取您系统上碰巧安装的任何mime.types
文件,并构建了从扩展名到MIME 类型的映射。在我的 Big Sur Mac 上,它以 1023 个这样的映射结束。以上是关于有没有一种在事先不知道文件类型的情况下使用 SMTP 在 python 中发送电子邮件附件的快速方法?的主要内容,如果未能解决你的问题,请参考以下文章
Ada - (Streams) 如何在事先不知道字符串长度的情况下正确调用 String'Read()