ChatGPT解决这个技术问题 Extra ChatGPT

如何发送电子邮件附件?

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

这是一个简单的实现,可以附加多个文件,甚至在要嵌入图像的情况下引用它们。 datamakessense.com/…
我发现这个有用的 drupal.org/project/mimemail/issues/911612 证明图像附件需要附加到相关类型的子部件。如果您将图像附加到根 MIME 部分,图像可以显示在附加项目列表中,并在 Outlook365 等客户端中进行预览。

O
Oli

这是另一个:

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()

和第一个例子差不多……不过应该更容易上手。


@user589983 为什么不像这里的任何其他用户那样建议编辑?我已将其余对 file 的引用更改为 f
Python3 开发人员注意事项:模块“email.Utils”已重命名为“email.utils”
对于 python2.5+,使用 MIMEApplication 更容易 - 将循环的前三行减少为:part = MIMEApplication(open(f, 'rb').read())
发送的电子邮件中未显示主题。仅在将行更改为 msg['Subject']=subject 后才起作用。我使用python 2.7。
E
Ehsan Iran-Nejad

这是从 Oli 为 python 3 修改的版本

import smtplib
from pathlib import Path
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 (list[str]): to name(s)
        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(Path(path).name))
        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()

send_to 应该是 list[str]
对我来说最好的答案,但有一个小错误:将 import pathlib 替换为 from pathlib import Path
迄今为止最好的答案。这应该是问题的解决方案。
@RubenFlam-Shepherd 谢谢。我更新了答案并删除了引号
Pyhon 标准库中的 email 模块在 Python 3.6 中进行了大修,使其更具逻辑性、通用性和简洁性;新代码应针对(不再是非常)新的 EmailMessage API。可能会丢弃这段代码并从 the Python email examples documentation. 中的现代代码重新开始
v
vinzee

这是我最终使用的代码:

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())

代码与 Oli 的帖子大致相同。

基于 Binary file email attachment problem 帖子的代码。


好答案。如果它还包含添加示例正文文本的代码,那就太好了。
请注意,在电子邮件库的现代版本中 - 模块导入是不同的。例如:from email.mime.base import MIMEBase
在 windows 上使用 python3.10 我有这个错误 AttributeError: 'MIMEMultipart' object has no attribute 'encode'
O
Oli
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()

改编自 here


不完全是我要找的。该文件作为电子邮件正文发送。第 6 行和第 7 行也缺少括号。我觉得我们越来越近了
电子邮件是纯文本,这正是 smtplib 所支持的。要发送附件,请将它们编码为 MIME 消息并以纯文本电子邮件的形式发送。不过有一个新的 Python 电子邮件模块:docs.python.org/library/email.mime.html
@katrienlalex 一个可行的例子可以帮助我理解
你确定上面的例子不起作用吗?我手边没有 SMTP 服务器,但我查看了 msg.as_string(),它看起来确实像 MIME 多部分电子邮件的正文。维基百科解释 MIME:en.wikipedia.org/wiki/MIME
Line 6, in <module> msg.attach(MIMEText(file("text.txt").read())) NameError: name 'file' is not defined
S
Sudarshan

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()

确保在您的 Gmail 帐户中允许“less secure apps


F
Ferrarezi

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()

用法:

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...
)

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


A
Andrade

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

#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()

它基于官方的 Django documentation


在您的情况下,您必须安装 django 才能发送电子邮件...它无法正确回复问题
@comte '因为 python 只用于 Django,对吗?
@Auspex 这就是我的观点;-) 这就像安装 LibreOffice 来编辑配置文件......
我觉得这很有帮助且内容丰富。只导入了一个模块,与其他人跳过的 MIME 箍相比,它的使用非常简单和优雅。相比之下,在您的示例中,LibreOffice 比记事本更难使用。
这太愚蠢了,这不是本地的做法。
A
Antony Fuentes

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

这里的主要区别在于,使用这种方法,您可以使用 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())

我希望这有帮助! :-)


s
sdoshi
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import mimetypes
import email.mime.application

smtp_ssl_host = 'smtp.gmail.com'  # smtp.mail.yahoo.com
smtp_ssl_port = 465
s = smtplib.SMTP_SSL(smtp_ssl_host, smtp_ssl_port)
s.login(email_user, email_pass)


msg = MIMEMultipart()
msg['Subject'] = 'I have a picture'
msg['From'] = email_user
msg['To'] = email_user

txt = MIMEText('I just bought a new camera.')
msg.attach(txt)

filename = 'introduction-to-algorithms-3rd-edition-sep-2010.pdf' #path to file
fo=open(filename,'rb')
attach = email.mime.application.MIMEApplication(fo.read(),_subtype="pdf")
fo.close()
attach.add_header('Content-Disposition','attachment',filename=filename)
msg.attach(attach)
s.send_message(msg)
s.quit()

如需解释,您可以使用正确解释的此链接https://medium.com/@sdoshi579/to-send-an-email-along-with-attachment-using-smtp-7852e77623


A
Abdul Haseeb
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import smtplib

msg = MIMEMultipart()

password = "password"
msg['From'] = "from_address"
msg['To'] = "to_address"
msg['Subject'] = "Attached Photo"
msg.attach(MIMEImage(file("abc.jpg").read()))
file = "file path"
fp = open(file, 'rb')
img = MIMEImage(fp.read())
fp.close()
msg.attach(img)
server = smtplib.SMTP('smtp.gmail.com: 587')
server.starttls()
server.login(msg['From'], password)
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()

您好,欢迎您,请在回答问题时始终发布您的答案解释,以便更好地理解
m
miksus

我知道这是一个老问题,但我认为必须有比其他示例更简单的方法,因此我制作了一个库,可以干净地解决这个问题而不会污染你的代码库。包含附件非常简单:

from redmail import EmailSender
from pathlib import Path

# Configure an email sender
email = EmailSender(
    host="<SMTP HOST>", port=0,
    user_name="me@example.com", password="<PASSWORD>"
)

# Send an email
email.send(
    sender="me@example.com",
    receivers=["you@example.com"],
    subject="An example email"
    attachments={
        "myfile.txt": Path("path/to/a_file.txt"),
        "myfile.html": "<h1>Content of a HTML attachment</h1>"
    }
)

您也可以直接附加 bytes、Pandas DataFrame(根据密钥中的文件扩展名转换为格式)、Matplotlib Figure 或 Pillow Image。该库很可能是电子邮件发件人所需的所有功能(不仅仅是附件)。

安装:

pip install redmail

以任何你喜欢的方式使用它。我还编写了大量文档:https://red-mail.readthedocs.io/en/latest/


port=0 看起来像个蹩脚的笑话。您应该期望找到 587、465 或 25 之一;但可能会咨询您要使用的服务的电子邮件管理员或公共文档。
@tripleee 这甚至不是一个笑话。 Smtplib has port=0 by default。无论您对端口的看法如何,如何连接到特定的 SMTP 服务器都超出了此问题的范围。
嗯,TIL,谢谢你让我明白这一点。我想知道 smtplib 文档中的“操作系统默认值”是什么意思;我想它必须是 25 到处都是?
简直太棒了。这简化了多个附件,基本上简化了整个电子邮件的混乱。在 Anaconda 中可用。布拉沃米克苏斯。
t
tripleee

因为这里有很多关于 Python 3 的答案,但没有一个显示如何使用 Python 3.6 中的大修 email 库,这里是当前 email examples documentation. 的快速复制+粘贴(我已经对其进行了一些删节以删除诸如猜测正确的 MIME 类型。)

以 Python > 3.5 为目标的现代代码不应再使用 email.message.Message API(包括各种 MIMETextMIMEMultipartMIMEBase 等类)或更旧的 mimetypes mumbo jumbo。

from email.message import EmailMessage
import smtplib

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")

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

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

现代的 email.message.EmailMessage API 现在比旧版本的库更加通用和合乎逻辑。文档中的演示文稿仍然存在一些问题(例如,如何更改附件的 Content-Disposition: 并不明显;对于大多数新手来说,关于 policy 模块的讨论可能太晦涩难懂),从根本上说,你仍然需要对 MIME 结构应该是什么样子有一些了解(尽管库现在终于处理了很多关于它的细节)。或许请参阅 What are the "parts" in a multipart email? 以获得简要介绍。

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


我非常喜欢只使用 email.message.EmailMessage API 的想法。您能否为具有多个具有不同子类型的附件的函数提供代码示例。
链接的文档有几个示例。但简而言之,for attachment, main, sub in (("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)。
A
Alex Potapenko

此处当前给出的答案都不能与 GMail、Outlook 2016 和其他不支持 RFC 2231 的客户端(例如,请参阅 here)的文件名中的非 ASCII 符号一起正常工作。下面的 Python 3 代码改编自其他一些 stackoverflow 答案(抱歉,没有保存原始链接)和 Python 2.7 的 odoo/openerp 代码(参见 ir_mail_server.py)。它可以与 GMail 和其他软件一起正常工作,并且还使用 SSL。

import smtplib, ssl
from os.path import basename
from email.mime.base import MIMEBase
from mimetypes import guess_type
from email.encoders import encode_base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email.charset import Charset


def try_coerce_ascii(string_utf8):
    """Attempts to decode the given utf8-encoded string
       as ASCII after coercing it to UTF-8, then return
       the confirmed 7-bit ASCII string.
 
       If the process fails (because the string
       contains non-ASCII characters) returns ``None``.
    """
    try:
        string_utf8.encode('ascii')
    except UnicodeEncodeError:
        return
    return string_utf8


def encode_header_param(param_text):
    """Returns an appropriate RFC 2047 encoded representation of the given
       header parameter value, suitable for direct assignation as the
       param value (e.g. via Message.set_param() or Message.add_header())
       RFC 2822 assumes that headers contain only 7-bit characters,
       so we ensure it is the case, using RFC 2047 encoding when needed.
 
       :param param_text: unicode or utf-8 encoded string with header value
       :rtype: string
       :return: if ``param_text`` represents a plain ASCII string,
                return the same 7-bit string, otherwise returns an
                ASCII string containing the RFC2047 encoded text.
    """
    if not param_text: return ""
    param_text_ascii = try_coerce_ascii(param_text)
    return param_text_ascii if param_text_ascii\
         else Charset('utf8').header_encode(param_text)


smtp_server = '<someserver.com>'
smtp_port = 465  # Default port for SSL
sender_email = '<sender_email@some.com>'
sender_password = '<PASSWORD>'
receiver_emails = ['<receiver_email_1@some.com>', '<receiver_email_2@some.com>']
subject = 'Test message'
message = """\
Hello! This is a test message with attachments.

This message is sent from Python."""

files = ['<path1>/файл1.pdf', '<path2>/файл2.png']


# Create a secure SSL context
context = ssl.create_default_context()

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

msg.attach(MIMEText(message))

for f in files:
    mimetype, _ = guess_type(f)
    mimetype = mimetype.split('/', 1)
    with open(f, "rb") as fil:
        part = MIMEBase(mimetype[0], mimetype[1])
        part.set_payload(fil.read())
        encode_base64(part)
    filename_rfc2047 = encode_header_param(basename(f))

    # The default RFC 2231 encoding of Message.add_header() works in Thunderbird but not GMail
    # so we fix it by using RFC 2047 encoding for the filename instead.
    part.set_param('name', filename_rfc2047)
    part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)
    msg.attach(part)

with smtplib.SMTP_SSL(smtp_server, smtp_port, context=context) as server:
    server.login(sender_email, sender_password)
    server.sendmail(sender_email, receiver_emails, msg.as_string())

我决定用这个版本。特别是因为文件名,在我的例子中,可以包含非 ASCII 字符。
Python 3.6+ 中更新的 email 库在这些方面更加透明和强大。它应该在没有您参与的情况下处理大部分这些细节;这是从您仍然在此处使用的旧 API 迁移的主要且相当令人信服的原因之一。
T
TonyRyan

下面是我从 SoccerPlayer 的帖子 Here 中找到的内容以及使我更容易附加 xlsx 文件的以下链接的组合。 Found Here

file = 'File.xlsx'
username=''
password=''
send_from = ''
send_to = 'recipient1 , recipient2'
Cc = 'recipient'
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = send_to
msg['Cc'] = Cc
msg['Date'] = formatdate(localtime = True)
msg['Subject'] = ''
server = smtplib.SMTP('smtp.gmail.com')
port = '587'
fp = open(file, 'rb')
part = MIMEBase('application','vnd.ms-excel')
part.set_payload(fp.read())
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment', filename='Name File Here')
msg.attach(part)
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.ehlo()
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(send_from, send_to.split(',') + msg['Cc'].split(','), msg.as_string())
smtp.quit()

J
John Rua

使用我的代码,您可以使用 gmail 发送电子邮件附件,您需要:

在“您的 SMTP EMAIL HERE”处设置您的 gmail 地址

在“YOUR SMTP PASSWORD HERE_”处设置您的 gmail 帐户密码

在 ___EMAIL TO RECEIVE THE MESSAGE_ 部分,您需要设置目标电子邮件地址。

报警通知是主题,

有人进了房间,附图是尸体

["/home/pi/webcam.jpg"] 是一个图片附件。

#!/usr/bin/env python
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os

USERNAME = "___YOUR SMTP EMAIL HERE___"
PASSWORD = "__YOUR SMTP PASSWORD HERE___"

def sendMail(to, subject, text, files=[]):
    assert type(to)==list
    assert type(files)==list

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

    msg.attach( MIMEText(text) )

    for file in files:
        part = MIMEBase('application', "octet-stream")
        part.set_payload( open(file,"rb").read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"'
                       % os.path.basename(file))
        msg.attach(part)

    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo_or_helo_if_needed()
    server.starttls()
    server.ehlo_or_helo_if_needed()
    server.login(USERNAME,PASSWORD)
    server.sendmail(USERNAME, to, msg.as_string())
    server.quit()

sendMail( ["___EMAIL TO RECEIVE THE MESSAGE__"],
        "Alarm notification",
        "Someone has entered the room, picture attached",
        ["/home/pi/webcam.jpg"] )

好久不见!很高兴看到您正确地归因于您的代码并将其直接包含在答案中。但是,通常不赞成在多个问题上复制粘贴相同的答案代码。如果他们真的可以用相同的解决方案解决,您应该flag the questions as duplicates改为。
C
Charlie Parker

您还可以在电子邮件中指定所需的附件类型,例如我使用 pdf:

def send_email_pdf_figs(path_to_pdf, subject, message, destination, password_path=None):
    ## credits: http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script
    from socket import gethostname
    #import email
    from email.mime.application import MIMEApplication
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import smtplib
    import json

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    with open(password_path) as f:
        config = json.load(f)
        server.login('me@gmail.com', config['password'])
        # Craft message (obj)
        msg = MIMEMultipart()

        message = f'{message}\nSend from Hostname: {gethostname()}'
        msg['Subject'] = subject
        msg['From'] = 'me@gmail.com'
        msg['To'] = destination
        # Insert the text to the msg going by e-mail
        msg.attach(MIMEText(message, "plain"))
        # Attach the pdf to the msg going by e-mail
        with open(path_to_pdf, "rb") as f:
            #attach = email.mime.application.MIMEApplication(f.read(),_subtype="pdf")
            attach = MIMEApplication(f.read(),_subtype="pdf")
        attach.add_header('Content-Disposition','attachment',filename=str(path_to_pdf))
        msg.attach(attach)
        # send msg
        server.send_message(msg)

灵感/致谢:http://linuxcursor.com/python-programming/06-how-to-send-pdf-ppt-attachment-with-html-body-in-python-script


S
Saisaaketh Sambana

试试这个我希望这可能会有所帮助

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 = "youremailhere"
toaddr = input("Enter The Email Adress You want to send to: ")
   
# instance of MIMEMultipart
msg = MIMEMultipart()
  
# storing the senders email address  
msg['From'] = fromaddr
  
# storing the receivers email address 
msg['To'] = toaddr
  
# storing the subject 
msg['Subject'] = input("What is the Subject:\t")
# string to store the body of the mail
body = input("What is the body:\t")
  
# attach the body with the msg instance
msg.attach(MIMEText(body, 'plain'))
  
# open the file to be sent 
filename = input("filename:")
attachment = open(filename, "rb")
  
# instance of MIMEBase and named as p
p = MIMEBase('application', 'octet-stream')
  
# To change the payload into encoded form
p.set_payload((attachment).read())
  
# encode into base64
encoders.encode_base64(p)
   
p.add_header('Content-Disposition', "attachment; filename= %s" % filename)
  
# attach the instance 'p' to instance 'msg'
msg.attach(p)
  
# creates SMTP session
s = smtplib.SMTP('smtp.gmail.com', 587)
  
# start TLS for security
s.starttls()
  
# Authentication
s.login(fromaddr, "yourpaswordhere)
  
# Converts the Multipart msg into a string
text = msg.as_string()
  
# sending the mail
s.sendmail(fromaddr, toaddr, text)
  
# terminating the session
s.quit()

T
Titus Cheserem

让我的脚本发送通用附件有点麻烦,但经过一些研究和浏览这篇文章的文章后,我终于想出了以下内容

# to query:
import sys
import ast
from datetime import datetime

import smtplib
import mimetypes
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.text import MIMEText

from dotenv import load_dotenv, dotenv_values

load_dotenv()  # load environment variables from .env

'''
sample .env file
# .env file
SECRET_KEY="gnhfpsjxxxxxxxx"
DOMAIN="GMAIL"
TOP_LEVEL_DOMAIN="COM"
EMAIL="CHESERExxxxxx@${DOMAIN}.${TOP_LEVEL_DOMAIN}"
TO_ADDRESS = ("cheseremxxxxx@gmail.com","cheserek@gmail.com")#didn't use this in the code but you can load recipients from here
'''

import smtplib

tls_port = 587
ssl_port = 465
smtp_server_domain_names = {'GMAIL': ('smtp.gmail.com', tls_port, ssl_port),
                            'OUTLOOK': ('smtp-mail.outlook.com', tls_port, ssl_port),
                            'YAHOO': ('smtp.mail.yahoo.com', tls_port, ssl_port),
                            'AT&T': ('smtp.mail.att.net', tls_port, ssl_port),
                            }


# todo: Ability to choose mail server provider
# auto read in from the dictionary the respective mail server address and the tls and ssl ports

class Bimail:
    def __init__(self, subject, recipients):
        self.subject = subject
        self.recipients = recipients
        self.htmlbody = ''
        self.mail_username = 'will be loaded from .env file'
        self.mail_password = 'loaded from .env file as well'
        self.attachments = []

    # Creating an smtp object
    # todo: if gmail passed in use gmail's dictionary values

    def setup_mail_client(self, domain_key_to_use="GMAIL",
                          email_servers_domains_dict=smtp_server_domain_names):
        """

        :param report_pdf:
        :type to_address: str
        """
        smtpObj = None
        encryption_status = True
        config = dotenv_values(".env")
        # check if the domain_key exists from within the available email-servers-domains dict file passed in
        # else throw an error

        # read environment file to get the Domain to be used
        if f"{domain_key_to_use}" in email_servers_domains_dict.keys():
            # if the key is found do the following
            # 1.extract the domain,tls,ssl ports from email_servers dict for use in program
            try:
                values_tuple = email_servers_domains_dict.get(f"{domain_key_to_use}")
                ssl_port = values_tuple[2]
                tls_port = values_tuple[1]
                smtp_server = values_tuple[0]

                smtpObj = smtplib.SMTP(smtp_server, tls_port)
                print(f"Success connect with tls on {tls_port}")
                print('Awaiting for connection encryption via startttls()')
                encryption_status = False

            except:
                print(f"Failed connection via tls on port {tls_port}")
                try:
                    smtpObj = smtplib.SMTP_SSL(smtp_server, ssl_port)
                    print(f"Success connect with ssl on {ssl_port}")
                    encryption_status = True
                except:
                    print(f"Failed connection via ssl on port {ssl_port}")
            finally:
                print("Within Finally block")
                if not smtpObj:
                    print("Failed!!!  no Internet connection")
                else:
                    # if connection channel is unencrypted via the use of tls encrypt it
                    if not encryption_status:
                        status = smtpObj.starttls()
                        if status[0] == 220:
                            print("Successfully Encrypted tls channel")

                    print("Successfully Connected!!!! Requesting Login")
                    # Loading .env file values to config variable
                    #load Login Creds from ENV File
                    self.mail_username = f'{config.get("EMAIL")}'
                    self.mail_password = f'{cofig.get("SECRET_KEY")}'


                    status = smtpObj.login(self.mail_usernam,self.mail_password) 

                    if status[0] == 235:
                        print("Successfully Authenticated User to xxx account")
                        success = self.send(smtpObj, f'{config.get("EMAIL")}')
                        if not bool(success):
                            print(f"Success in Sending Mail to  {success}")
                            print("Disconnecting from Server INstance")
                            quit_result = smtpObj.quit()

                        else:
                            print(f"Failed to Post {success}!!!")
                            print(f"Quiting anyway !!!")
                            quit_result = smtpObj.quit()
                    else:
                        print("Application Specific Password is Required")
        else:

            print("World")

    def send(self,smtpObj,from_address):
        msg = MIMEMultipart('alternative')
        msg['From'] = from_address
        msg['Subject'] = self.subject
        msg['To'] = ", ".join(self.recipients)  # to must be array of the form ['mailsender135@gmail.com']
        msg.preamble = "preamble goes here"
        # check if there are attachments if yes, add them
        if self.attachments:
            self.attach(msg)
        # add html body after attachments
        msg.attach(MIMEText(self.htmlbody, 'html'))
        # send
        print(f"Attempting Email send to the following addresses {self.recipients}")
        result = smtpObj.sendmail(from_address, self.recipients,msg.as_string())
        return result
        

    def htmladd(self, html):
        self.htmlbody = self.htmlbody + '<p></p>' + html

    def attach(self, msg):
        for f in self.attachments:

            ctype, encoding = mimetypes.guess_type(f)
            if ctype is None or encoding is not None:
                ctype = "application/octet-stream"

            maintype, subtype = ctype.split("/", 1)

            if maintype == "text":
                fp = open(f)
                # Note: we should handle calculating the charset
                attachment = MIMEText(fp.read(), _subtype=subtype)
                fp.close()
            elif maintype == "image":
                fp = open(f, "rb")
                attachment = MIMEImage(fp.read(), _subtype=subtype)
                fp.close()

            elif maintype == "ppt":
                fp = open(f, "rb")
                attachment = MIMEApplication(fp.read(), _subtype=subtype)
                fp.close()

            elif maintype == "audio":
                fp = open(f, "rb")
                attachment = MIMEAudio(fp.read(), _subtype=subtype)
                fp.close()
            else:
                fp = open(f, "rb")
                attachment = MIMEBase(maintype, subtype)
                attachment.set_payload(fp.read())
                fp.close()
                encoders.encode_base64(attachment)
            attachment.add_header("Content-Disposition", "attachment", filename=f)
            attachment.add_header('Content-ID', '<{}>'.format(f))
            msg.attach(attachment)

    def addattach(self, files):
        self.attachments = self.attachments + files


# example below
if __name__ == '__main__':
    # subject and recipients
    mymail = Bimail('Sales email ' + datetime.now().strftime('%Y/%m/%d'),
                    ['cheseremxx@gmail.com', 'tkemboxxx@gmail.com'])
    # start html body. Here we add a greeting.
    mymail.htmladd('Good morning, find the daily summary below.')
    # Further things added to body are separated by a paragraph, so you do not need to worry about newlines for new sentences
    # here we add a line of text and an html table previously stored in the variable
    mymail.htmladd('Daily sales')
    mymail.addattach(['htmlsalestable.xlsx'])
    # another table name + table
    mymail.htmladd('Daily bestsellers')
    mymail.addattach(['htmlbestsellertable.xlsx'])
    # add image chart title
    mymail.htmladd('Weekly sales chart')
    # attach image chart
    mymail.addattach(['saleschartweekly.png'])
    # refer to image chart in html
    mymail.htmladd('<img src="cid:saleschartweekly.png"/>')
    # attach another file
    mymail.addattach(['MailSend.py'])
    # send!
    
    mymail.setup_mail_client( domain_key_to_use="GMAIL",email_servers_domains_dict=smtp_server_domain_names)

此代码似乎是为 Python 3.5 或更早版本编写的。 email 库在 3.6 中进行了大修,现在更加通用和合乎逻辑。可能扔掉你所拥有的并从examples from the email documentation.重新开始
R
Rachel Gomez

所有电子邮件程序的过程几乎相同:

- 打开一个新的电子邮件消息窗口,通常通过单击“新消息”或“撰写电子邮件”图标或 CTRL + N 键盘快捷键。

- 单击带有“附加文件”或类似内容的回形针图标的菜单项。

- 浏览计算机的文件夹并单击以选择要附加的文件/文件夹。在大多数情况下,您可以通过在单击每个文件的同时按住 CTRL 键来选择多个文件。

单击“打开”或“选择文件”或其他类似按钮将文件附加到您的电子邮件中。

- 然后继续撰写您的电子邮件。

问候,雷切尔·戈麦斯