我有问题理解如何使用Python电子邮件附件。我已经成功地通过smtplib电子邮件发送了简单的消息。有人能解释一下如何在电子邮件中发送附件吗?我知道网上还有其他的帖子,但作为一个Python初学者,我发现它们很难理解。
当前回答
在让我的脚本发送通用附件时遇到了一点麻烦,但在做了一些研究和浏览了这篇文章后,我终于想出了以下几点
# 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 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()
我能找到的最简单的代码是:
#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文档
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帐户上允许“不太安全的应用程序”
这是我最终使用的代码:
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的帖子大致相同。
代码基于二进制文件电子邮件附件问题的帖子。
这是另一个:
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中进行热编码?
- 如何嵌入HTML到IPython输出?
- 在Python生成器上使用“send”函数的目的是什么?
- 是否可以将已编译的.pyc文件反编译为.py文件?
- Django模型表单对象的自动创建日期
- 在Python中包装长行
- 如何计算两个时间串之间的时间间隔
- 我如何才能找到一个Python函数的参数的数量?
- 您可以使用生成器函数来做什么?
- 将Python诗歌与Docker集成
- 提取和保存视频帧
- 使用请求包时出现SSL InsecurePlatform错误
- 如何检索Pandas数据帧中的列数?
- except:和except的区别:
- 错误:“字典更新序列元素#0的长度为1;2是必需的”