我有问题理解如何使用Python电子邮件附件。我已经成功地通过smtplib电子邮件发送了简单的消息。有人能解释一下如何在电子邮件中发送附件吗?我知道网上还有其他的帖子,但作为一个Python初学者,我发现它们很难理解。
当前回答
这是另一个:
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()
这和第一个例子差不多……但顺便来一下应该更容易些。
其他回答
因为这里有很多关于Python 3的答案,但没有一个说明如何使用Python 3.6中经过彻底检查的电子邮件库,这里是从当前电子邮件示例文档中快速复制+粘贴。 (我略去了一些内容,以去除猜测正确MIME类型之类的多余内容。)
以Python >3.5为目标的现代代码不应该再使用email.message.Message API(包括各种MIMEText、MIMEMultipart、MIMEBase等类)或更老的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)
The modern email.message.EmailMessage API is now quite a bit more versatile and logical than the older version of the library. There are still a few kinks around the presentation in the documentation (it's not obvious how to change the Content-Disposition: of an attachment, for example; and the discussion of the policy module is probably too obscure for most newcomers) and fundamentally, you still need to have some sort of idea of what the MIME structure should look like (though the library now finally takes care of a lot of the nitty-gritty around that). Perhaps see What are the "parts" in a multipart email? for a brief introduction.
Using localhost as your SMTP server obviously only works if you actually have an SMTP server running on your local computer. Properly getting email off your system is a fairly complex separate question. For simple requirements, probably use your existing email account and your provider's email server (search for examples of using port 587 with Google, Yahoo, or whatever you have - what exactly works depends somewhat on the provider; some will only support port 465, or legacy port 25 which is however now by and large impossible to use on public-facing servers because of spam filtering).
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配置。
其他的答案也很好,但我还是想分享一种不同的方法,以防有人正在寻找替代方案。
主要的区别是,使用这种方法,你可以使用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())
我希望这能有所帮助!: -)
我能找到的最简单的代码是:
#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文档
在让我的脚本发送通用附件时遇到了一点麻烦,但在做了一些研究和浏览了这篇文章后,我终于想出了以下几点
# 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中的assertEquals和assertEqual
- 如何保持Python打印不添加换行符或空格?
- 为什么Python的无穷散列中有π的数字?
- Python 3.7数据类中的类继承
- 如何在PyTorch中初始化权重?
- 计数唯一的值在一列熊猫数据框架像在Qlik?
- 使用Pandas将列转换为行
- 从matplotlib中的颜色映射中获取单个颜色
- 将Pandas或Numpy Nan替换为None以用于MysqlDB
- 使用pandas对同一列进行多个聚合
- 使用Python解析HTML
- 如何在Jenkins中设置发件人地址?
- django MultiValueDictKeyError错误,我如何处理它
- 如何在for循环期间修改列表条目?
- 我如何在Django中创建一个鼻涕虫?