如何发送电子邮件附件?

Ric*_*ard 262 python email

我在理解如何使用Python向附件发送电子邮件时遇到问题.我已成功通过电子邮件发送简单邮件smtplib.有人可以解释如何在电子邮件中发送附件.我知道网上还有其他帖子,但作为Python初学者,我觉得很难理解.

Oli*_*Oli 387

这是另一个:

import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate


def send_mail(send_from, send_to, subject, text, files=None,
              server="127.0.0.1"):
    assert isinstance(send_to, list)

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil:
            part = MIMEApplication(
                fil.read(),
                Name=basename(f)
            )
        # After the file is closed
        part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
        msg.attach(part)


    smtp = smtplib.SMTP(server)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()
Run Code Online (Sandbox Code Playgroud)

它与第一个例子大致相同......但它应该更容易投入.

  • @ user589983为什么不建议像其他任何用户一样编辑?我已将对`file`的剩余引用更改为`f`. (11认同)
  • 关于Python3开发人员的注意事项:模块"email.Utils"已重命名为"email.utils" (8认同)
  • 小心可变的默认值:http://stackoverflow.com/questions/101268/hidden-features-of-python/113198#113198 (7认同)
  • 对于python2.5 +它更容易使用[MIMEApplication](http://docs.python.org/2/library/email.mime.html#email.mime.application.MIMEApplication)代替 - 减少t的前三行他循环:`part = MIMEApplication(open(f,'rb').read())` (6认同)
  • 主题未显示在发送的电子邮件中.仅在将行更改为msg ['Subject'] = subject后才能工作.我使用python 2.7. (5认同)
  • Content-dispostion不起作用请参阅http://stackoverflow.com/a/3363538/128629或http://stackoverflow.com/a/16509278/128629以获取正确的方法 (3认同)
  • 某些邮件客户端(在我的情况下是Thunderbird)无法正确解释通过此方法发送的"*.txt"附件.要纠正这个问题,只需将`MIMEBase('application','octet-stream')`更改为`MIMEBase('application','base64')`.请编辑答案以反映这一点. (2认同)
  • @Oli标题错误:你错过的部分"Content-Type标题的附加参数取自关键字参数(或传递给_params参数)." 用于指定您想要新标题的文件名 (2认同)
  • 是的 - 这是不正确的.您需要像在pcboy的答案中那样传递标题,即使在Python 2上也是如此.此外,除了Content_Disposition之外,我还必须将name ='foo.pdf'传递给MIMEApplication,以便在我的电子邮件客户端(Gmail)中正确注册文件名.请编辑答案! (2认同)

Ric*_*ard 64

这是我最终使用的代码:

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders


SUBJECT = "Email Data"

msg = MIMEMultipart()
msg['Subject'] = SUBJECT 
msg['From'] = self.EMAIL_FROM
msg['To'] = ', '.join(self.EMAIL_TO)

part = MIMEBase('application', "octet-stream")
part.set_payload(open("text.txt", "rb").read())
Encoders.encode_base64(part)

part.add_header('Content-Disposition', 'attachment; filename="text.txt"')

msg.attach(part)

server = smtplib.SMTP(self.EMAIL_SERVER)
server.sendmail(self.EMAIL_FROM, self.EMAIL_TO, msg.as_string())
Run Code Online (Sandbox Code Playgroud)

代码与Oli的帖子大致相同.谢谢大家

代码基于二进制文件电子邮件附件问题的帖子.

  • 请注意,在电子邮件库的现代版本中 - 模块导入是不同的。例如:`from email.mime.base import MIMEBase` (5认同)
  • 好答案。如果它还包含添加示例正文的代码,那就更好了。 (2认同)

Ehs*_*jad 63

这是Olipython 3 的修改版本

import smtplib
import os.path as op
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email import encoders


def send_mail(send_from, send_to, subject, message, files=[],
              server="localhost", port=587, username='', password='',
              use_tls=True):
    """Compose and send email with provided info and attachments.

    Args:
        send_from (str): from name
        send_to (str): to name
        subject (str): message title
        message (str): message body
        files (list[str]): list of file paths to be attached to email
        server (str): mail server host name
        port (int): port number
        username (str): server auth username
        password (str): server auth password
        use_tls (bool): use TLS mode
    """
    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(message))

    for path in files:
        part = MIMEBase('application', "octet-stream")
        with open(path, 'rb') as file:
            part.set_payload(file.read())
        encoders.encode_base64(part)
        part.add_header('Content-Disposition',
                        'attachment; filename="{}"'.format(op.basename(path)))
        msg.attach(part)

    smtp = smtplib.SMTP(server, port)
    if use_tls:
        smtp.starttls()
    smtp.login(username, password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.quit()
Run Code Online (Sandbox Code Playgroud)

  • 对我来说最好的答案,但有一个小错误:将 ```import pathlib``` 替换为 ```from pathlib import Path``` (2认同)
  • Pyhon 标准库中的“email”模块在 Python 3.6 中进行了彻底修改,使其更加逻辑化、通用且简洁;新代码应该针对(不再是非常)新的“EmailMessage” API。可能会丢弃此代码并使用 [Python `email` 示例文档中的现代代码重新开始。](https://docs.python.org/3/library/email.examples.html) (2认同)

Oli*_*Oli 27

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import smtplib

msg = MIMEMultipart()
msg.attach(MIMEText(file("text.txt").read()))
msg.attach(MIMEImage(file("image.png").read()))

# to send
mailer = smtplib.SMTP()
mailer.connect()
mailer.sendmail(from_, to, msg.as_string())
mailer.close()
Run Code Online (Sandbox Code Playgroud)

改编自这里.

  • 电子邮件是纯文本,这就是`smtplib`支持的.要发送附件,请将它们编码为MIME消息,并以明文电子邮件形式发送.但是有一个新的python电子邮件模块:http://docs.python.org/library/email.mime.html (2认同)
  • `第 6 行,在 <module> msg.attach(MIMEText(file("text.txt").read())) NameError: name 'file' 未定义` (2认同)

tri*_*eee 14

因为这里有很多关于 Python 3 的答案,但没有一个显示如何使用emailPython 3.6 中的大修库,所以这里是当前示例文档中的快速复制+粘贴email (我对它进行了一些删节,以消除诸如猜测正确的 MIME 类型之类的多余内容。)

针对 Python >3.5 的现代代码不应再使用email.message.MessageAPI(包括各种MIMETextMIMEMultipartMIMEBase类)或更旧的mimetypes胡言乱语。

from email.message import EmailMessage
import smtplib
from pathlib import Path

msg = EmailMessage()
msg["Subject"] = "Our family reunion"
msg["From"] = "me <sender@example.org>"
msg["To"] = "recipient <victim@example.net>"
# definitely don't mess with the .preamble

msg.set_content("Hello, victim! Look at these pictures")

picpath = Path("path/to/attachment.png")
with picpath.open("rb") as fp:
    msg.add_attachment(
        fp.read(),
        maintype="image", subtype="png",
        filename=picpath.name)

# Notice how smtplib now includes a send_message() method
with smtplib.SMTP("localhost") as s:
    s.send_message(msg)
Run Code Online (Sandbox Code Playgroud)

现在,现代email.message.EmailMessageAPI 比旧版本的库更加通用和合乎逻辑。文档中的演示仍然存在一些问题(Content-Disposition:例如,如何更改附件的格式并不明显;并且该policy模块的讨论对于大多数新手来说可能太晦涩),从根本上讲,您仍然需要一些知识MIME 结构应该是什么样子的想法(尽管该库现在终于处理了围绕它的许多细节)。也许请参阅多部分电子邮件中的“部分”是什么?进行简单介绍。

localhost显然,仅当您的本地计算机上实际运行着 SMTP 服务器时,才可以将其用作 SMTP 服务器。正确地从系统中获取电子邮件是一个相当复杂的独立问题。对于简单的要求,可以使用您现有的电子邮件帐户和提供商的电子邮件服务器(搜索使用 Google、Yahoo 或任何您拥有的端口 587 的示例 - 确切的工作原理在某种程度上取决于提供商;有些仅支持端口 465,或者旧端口 25 但现在由于垃圾邮件过滤的原因基本上不可能在面向公众的服务器上使用)。

  • 链接的文档有几个示例。但简而言之,`对于附件,主要,子在 (("path/to/image.png", "image", "png"), ("another/directory/revenge.pdf", "application", "pdf "), ("somewhere/else/abyss.xlsx", "application", "octet-stream")): with open(attachment, "rb") as fp: msg.add_attachment(fp.read(), maintype= main, subtype=sub)`(懒得查找 XLSX 的正确 MIME 类型;朋友们无论如何都不让朋友使用 Excel)。 (2认同)

Fer*_*ezi 6

Gmail版本,使用Python 3.6(请注意,您需要更改Gmail设置才能通过smtp发送电子邮件:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from os.path import basename


def send_mail(send_from: str, subject: str, text: str, 
send_to: list, files= None):

    send_to= default_address if not send_to else send_to

    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = ', '.join(send_to)  
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil: 
            ext = f.split('.')[-1:]
            attachedfile = MIMEApplication(fil.read(), _subtype = ext)
            attachedfile.add_header(
                'content-disposition', 'attachment', filename=basename(f) )
        msg.attach(attachedfile)


    smtp = smtplib.SMTP(host="smtp.gmail.com", port= 587) 
    smtp.starttls()
    smtp.login(username,password)
    smtp.sendmail(send_from, send_to, msg.as_string())
    smtp.close()
Run Code Online (Sandbox Code Playgroud)

用法:

username = 'my-address@gmail.com'
password = 'top-secret'
default_address = ['my-address2@gmail.com'] 

send_mail(send_from= username,
subject="test",
text="text",
send_to= None,
files= # pass a list with the full filepaths here...
)
Run Code Online (Sandbox Code Playgroud)

要与任何其他电子邮件提供商一起使用,只需更改smtp配置即可.


And*_*ade 5

我能得到的最简单的代码是:

#for attachment email
from django.core.mail import EmailMessage

    def attachment_email(request):
            email = EmailMessage(
            'Hello', #subject
            'Body goes here', #body
            'MyEmail@MyEmail.com', #from
            ['SendTo@SendTo.com'], #to
            ['bcc@example.com'], #bcc
            reply_to=['other@example.com'],
            headers={'Message-ID': 'foo'},
            )

            email.attach_file('/my/path/file')
            email.send()
Run Code Online (Sandbox Code Playgroud)

它基于官方的Django 文档

  • @Auspex 这就是我的观点 ;-) 这就像安装 LibreOffice 来编辑配置文件...... (6认同)
  • 在您的情况下,您必须安装 django 才能发送电子邮件......它没有正确回复问题 (3认同)

Ant*_*via 5

其他答案非常好,但我仍然想分享一种不同的方法,以防有人正在寻找替代方案。

这里的主要区别在于,使用这种方法,您可以使用 HTML/CSS 来格式化您的消息,这样您就可以发挥创意并为您的电子邮件添加一些样式。尽管您没有被强制使用 HTML,但您仍然可以仅使用纯文本。

请注意,此功能接受将电子邮件发送给多个收件人,还允许附加多个文件。

我只在 Python 2 上尝试过这个,但我认为它在 3 上也应该可以正常工作:

import os.path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

def send_email(subject, message, from_email, to_email=[], attachment=[]):
    """
    :param subject: email subject
    :param message: Body content of the email (string), can be HTML/CSS or plain text
    :param from_email: Email address from where the email is sent
    :param to_email: List of email recipients, example: ["a@a.com", "b@b.com"]
    :param attachment: List of attachments, exmaple: ["file1.txt", "file2.txt"]
    """
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = ", ".join(to_email)
    msg.attach(MIMEText(message, 'html'))

    for f in attachment:
        with open(f, 'rb') as a_file:
            basename = os.path.basename(f)
            part = MIMEApplication(a_file.read(), Name=basename)

        part['Content-Disposition'] = 'attachment; filename="%s"' % basename
        msg.attach(part)

    email = smtplib.SMTP('your-smtp-host-name.com')
    email.sendmail(from_email, to_email, msg.as_string())
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助!:-)


Sud*_*han 5

使用python 3的另一种方式(如果有人正在搜索):

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

fromaddr = "sender mail address"
toaddr = "receiver mail address"

msg = MIMEMultipart()

msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "SUBJECT OF THE EMAIL"

body = "TEXT YOU WANT TO SEND"

msg.attach(MIMEText(body, 'plain'))

filename = "fileName"
attachment = open("path of file", "rb")

part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)

msg.attach(part)

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(fromaddr, "sender mail password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
Run Code Online (Sandbox Code Playgroud)

确保在您的Gmail帐户中允许“ 安全性较低的应用程序