我有问题理解如何使用Python电子邮件附件。我已经成功地通过smtplib电子邮件发送了简单的消息。有人能解释一下如何在电子邮件中发送附件吗?我知道网上还有其他的帖子,但作为一个Python初学者,我发现它们很难理解。


当前回答

这是我最终使用的代码:

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的帖子大致相同。

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

其他回答

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配置。

下面是Oli为python3编写的修改版本

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

下面是Python 3.6及更新版本的更新版本,使用Python标准库中经过大修的电子邮件模块的EmailMessage类。

import mimetypes
import os
import smtplib
from email.message import EmailMessage

username = "user@example.com"
password = "password"
smtp_url = "smtp.example.com"
port = 587


def send_mail(subject: str, send_from: str, send_to: str, message: str, directory: str, filename: str):
    # Create the email message
    msg = EmailMessage()
    msg['Subject'] = subject
    msg['From'] = send_from
    msg['To'] = send_to
    # Set email content
    msg.set_content(message)

    path = directory + filename

    if os.path.exists(path):
        ctype, encoding = mimetypes.guess_type(path)
        if ctype is None or encoding is not None:
            # No guess could be made, or the file is encoded (compressed), so
            # use a generic bag-of-bits type.
            ctype = 'application/octet-stream'
        maintype, subtype = ctype.split('/', 1)
        # Add email attachment
        with open(path, 'rb') as fp:
            msg.add_attachment(fp.read(),
                           maintype=maintype,
                           subtype=subtype,
                           filename=filename)

    smtp = smtplib.SMTP(smtp_url, port)
    smtp.starttls() # for using port 587
    smtp.login(username, password)
    smtp.send_message(msg)
    smtp.quit()

你可以在这里找到更多的例子。

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

这是我最终使用的代码:

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的帖子大致相同。

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