如何发送电子邮件附件?

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

516438 次浏览
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()

改编自在这里

这是另一个:

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

这和第一个例子差不多……但顺便来一下应该更容易些。

这是我最终使用的代码:

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

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

下面是python 3的Oli的修改版本

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

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

#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的文档

其他的答案也很好,但我还是想分享一种不同的方法,以防有人正在寻找替代方案。

主要的区别是,使用这种方法,你可以使用HTML/CSS来格式化你的邮件,所以你可以有创意,给你的电子邮件一些样式。虽然没有强制使用HTML,但仍然可以只使用纯文本。

注意,该函数接受将电子邮件发送给多个收件人,也允许附加多个文件。

我只在python2上尝试过,但我认为它在python3上也能正常工作:

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

我希望这对你有帮助!: -) < / em >

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

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帐户上允许“不太安全的应用程序

下面是我从SoccerPlayer的帖子在这里和下面的链接中找到的东西的组合,这使我更容易附加一个xlsx文件。在这里找到

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

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

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

设置你的gmail地址为“您的SMTP电子邮件在这里

将您的gmail帐户密码设置为“您的SMTP密码在这里_

阅读电子邮件来接收信息部分,你需要设置目标电子邮件地址。

报警通知是主语,

有人进了房间,附有照片是body

(“/ home /π/ 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"] )

你也可以在你的电子邮件中指定你想要的附件类型,例如我使用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

这里目前给出的答案都不能正确地使用GMail、Outlook 2016和其他不支持RFC 2231的客户机的文件名中的非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())

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

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

在让我的脚本发送通用附件时遇到了一点麻烦,但在做了一些研究和浏览了这篇文章后,我终于想出了以下几点

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

我知道这是一个老问题,但我认为一定有一种比其他例子更简单的方法来做到这一点,因此我做了一个库,在不污染代码库的情况下干净地解决这个问题。包含附件非常简单:

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/

因为这里有很多关于Python 3的答案,但没有一个显示如何使用Python 3.6中经过彻底检查的email库,这里是从当前email示例文档中快速复制+粘贴。 (我已经略去了一些,以去除诸如猜测正确的MIME类型之类的修饰。)

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

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结构应该是什么样子有一些想法(尽管现在库终于解决了很多关于它的细节问题)。也许可以参见“部分”是什么?在包含多个部分的电子邮件中?获得简要介绍。

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

下面是Python 3.6及更新版本的更新版本,使用Python 标准库中经过大修的email模块的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()

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