smtplib详解,发送邮件
创建邮箱账号
1、官网登录邮箱。
2、在邮箱的主界面找到“设置”,新版的主界面与旧版稍有不同,一般位于上方,齿轮状的即是。
3、点击齿轮状的设置标志,会弹出一个下拉菜单,在最后有我们找的关于邮箱的更多设置,点击进入。
4、此时切换到了设置面板,在设置区我们需要切换至账户界面,因为一般情况下pop3和smtp服务都是在这里设置的。
5、继续把网页往下拉,下面出现了我们要找的pop3和smtp服务设置。默认状态下显示为关闭。此时我们需要开启它,只需要点击开启就行了,然后点击保存。
6、填入验证码,保存设置成功。
新浪邮箱怎么不能用邮件客户端登陆了?
需要开启IMAP服务:
1、先登录自己的sina邮箱。
2、 单击窗口上的 "设置" 连接,进入到"邮箱设置"中,,切换到"账户"标签页,选中下方的开启“IMAP/SMTP”这时它的附加选项被激活,最后点击"保存更改"即可
发送邮件程序1
import smtplib server = "smtp.sina.com" fromaddr= "dachxxxx@sina.com" #须修改 toaddr = "8xxxx@qq.com" #须修改 msg = """ to:%s from:%s Hello,I am smtp server """ %(toaddr,fromaddr) s = smtplib.SMTP(server) s.set_debuglevel(1) s.login("dachxxx@sina.com","1535d05c76ca6xxx")#须修改 s.sendmail(fromaddr,toaddr,msg)
发送邮件程序2
参考:https://docs.python.org/2/library/email-examples.html
官网的缺少一个登陆认证,没有的话报错认证啥问题的
# Import smtplib for the actual sending function import smtplib # Import the email modules we'll need from email.mime.text import MIMEText # Open a plain text file for reading. For this example, assume that # the text file contains only ASCII characters. fp = open('textfile', 'r',encoding='utf-8') # Create a text/plain message msg = MIMEText(fp.read()) fp.close() # me == the sender's email address # you == the recipient's email address msg['Subject'] = 'The contents of %s' %("mcw") msg['From'] = 'dacxxx@sina.com' msg['To'] = '8xxxx@qq.com' # Send the message via our own SMTP server, but don't include the # envelope header. s = smtplib.SMTP('smtp.sina.com') s.login("dacxxxi@sina.com","1535d05c76ca6xxx") s.sendmail('dacxxx@sina.com', '8xxx@qq.com', msg.as_string()) s.quit()
结果:
解析HTML,需要添加html参数。
邮件模板
import smtplib # Import the email modules we'll need from email.mime.text import MIMEText # Open a plain text file for reading. For this example, assume that # the text file contains only ASCII characters. fp = open(r'templates/youjian.html', 'r',encoding='utf-8') # Create a text/plain message msg = MIMEText(fp.read(),'html') fp.close() # me == the sender's email address # you == the recipient's email address msg['Subject'] = 'The contents of %s' %("mcw") msg['From'] = 'dxx@sina.com' msg['To'] = '8xx@qq.com' # Send the message via our own SMTP server, but don't include the # envelope header. s = smtplib.SMTP('smtp.sina.com') s.login("dxxi@sina.com","15xx") s.sendmail('daxx@sina.com', '8xx@qq.com', msg.as_string()) s.quit()
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html lang="en"> <head> <meta charset="UTF-8"> <title>邮件提醒</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <!--<script type="text/javascript">--> <!--// var para = function () {--> <!--// }--> <!--var url = document.location.toString();--> <!--var arrUrl = url.split("?");--> <!--var para = arrUrl[1];--> <!--alert('===='+url);--> <!--</script>--> </head> <body style="margin: 0; padding: 0;"> <table align="center" border="0" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;"> <tr> <td> <div style="margin: 20px;text-align: center;margin-top: 50px"><img src="mcw.jpg" border="0" style="display:block;width: 100%;height: 100%"></div> </td> </tr> <tr> <td> <div style="border: #36649d 1px dashed;margin: 30px;padding: 20px"><label style="font-size: 22px;color: #36649d;font-weight: bold">恭喜您,注册成功!</label> <p style="font-size: 16px">亲爱的 <label style="font-weight: bold"> XXX先生/女士</label> 您好!欢迎加入xxx。 </p> <p style="font-size: 16px">您已于2022年9月23日充值成功,希望更好的为您服务!</p></div> </td> </tr> <tr> <td> <div style="margin: 40px"><p style="font-size: 16px">xxx管理团队</p> <p style="color:red;font-size: 14px ">(这是一封自动发送的邮件,请勿回复。)</p></div> </td> </tr> <tr> <td> <div align="right" style="margin: 40px;border-top: solid 1px gray" id="bottomTime"><p style="margin-right: 20px">xxx科技有限公司</p> <label style="margin-right: 20px">2018年08月30日</label></div> </td> </tr> </table> </body> </html>
使用jinja2定义自己的邮件html模板并发送邮件。
模板渲染和源码邮件发送代码如下:
import smtplib from email.mime.text import MIMEText from jinja2 import PackageLoader, Environment, FileSystemLoader dic={ "10.0.0.11":{"host":"10.0.0.11","hostname":"mcw01","mem":"20%"}, "10.0.0.12":{"host":"10.0.0.12","hostname":"mcw02","mem":"60%"}, "10.0.0.13":{"host":"10.0.0.13","hostname":"mcw03","mem":"55%"} } path_dir = r'C:\mcw\testt\templates\\' #模板文件所在的绝对路径 loader = FileSystemLoader(searchpath=path_dir) env = Environment(loader=loader) template = env.get_template("jinja2研究.html") # 第一步将模板文件放到这里 buf = template.render(dic=dic,) #第二步将模板文件中用来渲染的数据传进去。用变量接收渲染后的html页面源码 # with open(os.path.join(path_dir, "jinja2xxx.html"), "w" ) as fp: #可以将buf模板渲染后的数据重新写入另一个文件 # fp.write(buf) #这里重新写入文件的时候,中文会出现乱码 ####################上面是jinja2渲染模板,下面是将渲染后源码发送邮件出去###################################### msg = MIMEText(buf,'html') #似乎是加密后的数据。指明是html格式,将渲染后的页面源码buf传进去,作为消息页面展示 #我们将需要的数据已经渲染进来消息里面了 msg['Subject'] = 'The contents of %s' %("mcw") msg['From'] = 'dxx@sina.com' msg['To'] = '8xx@qq.com' s = smtplib.SMTP('smtp.sina.com') s.login("dxx@sina.com","1xx") s.sendmail('dxx@sina.com', '8xx@qq.com', msg.as_string()) s.quit()
下面是模板:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body > <div style="background-color: blue;width: 500px;height: 400px"> <table border="1" cellspacing="0" style="height: 150px;width: 100%"> <thead> <tr style="background-color: gold;"> <th>主机ip</th> <th>主机名</th> <th>内存使用率</th> </tr> </thead> <tbody> {% for k,foo in dic.items() %} <tr style="background-color: gold;"> <td>{{ foo.host }}</td> <td>{{ foo.hostname }}</td> <td>{{ foo.mem }}</td> </tr> {% endfor %} </tbody> </table> </div> </body> </html>
效果如下:执行程序后,模板渲染,然后渲染后的buf源码放到邮件的消息中,做邮件发送。我们还可以将渲染后的页面保存到另一个文件,但是保存会出现中文乱码。应该以wb的方式写入,或许就可以了把,或者直接wb方式写,是否需要编码后放进去呢?
如下,看着还是不错的,我们需要改改样式,改漂亮些。可以用来发送运维邮件通知等的。需要思考的是,图片和附件是如何加入到邮件中。这里的jinja2应该也是可以使用模板继承的方式去写的吧,不知道可不可以加入js。应该也是可以的吧
发送,抄送邮件并带上附件的函数
一个附件
效果如下:
程序如下:
#1.导包 import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import logging #2.定义发送邮件函数 def send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name): message = MIMEMultipart() message['From'] = MAIL_USERNAME # 发件人 message['To'] = ";".join(accept_list) # 收件人,将列表转换为字符串 message["Cc"] = ";".join(Cc_list) # 抄送人,将列表转换为字符串 message['Subject'] = SUBJECT # 邮件主题 message.attach(MIMEText(text, 'plain', 'utf-8')) # 格式化邮件内容,编码为utf-8 att1 = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') # 添加附件 att1["Content-Type"] = 'application/octet-stream' # 设置类型 att1["Content-Disposition"] = 'attachment; filename="{0}"'.format("test.xlsx") # 设置邮件用现实的名称,这里是格式化filename也就是邮件附件使用名称 message.attach(att1) try: mailServer = smtplib.SMTP(MAIL_SERVER, 25) # 25为端口号(邮件) # 登录邮箱 mailServer.login(MAIL_USERNAME, MAIL_PASSWORD) # 需要的是,邮箱的地址和授权密码 # 发送文件 mailServer.sendmail(MAIL_USERNAME, accept_list + Cc_list, message.as_string()) mailServer.close() # 关闭连接 return True except Exception as e: # logging.debug(e) print(e) return False #3.调用发送邮件函数 def main(): MAIL_SERVER = 'smtp.sina.com' # smtp服务器 MAIL_USERNAME = 'dxx@sina.com' # 发件人 MAIL_PASSWORD = '1xxx' # 发送者授权码 accept_list = ['89xx@qq.com',] # 收件人 Cc_list = ['89xx5@qq.com', '28xx@qq.com'] # 抄送人 SUBJECT = "我是邮件主题" # 主题 text = "邮件内容吗?" # 内容 file_name = r"C:\mcw\testt\templates\youjian.html" # 上传附件名称(当前路径) if send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name): logging.debug("Send mail succed!") else: logging.debug("Send mail failed") if __name__ == '__main__': main()
我们预览一下附件
就是我们的html页面
我再加一个附件。多个附件
如下,是多个附件的效果..第二个附件能看出是个图片了。如果是py程序,不支持查看
需要在main函数下添加第二个附件,加到发送函数的调用参数中
file_name2 = r"C:\mcw\testt\templates\mcw.jpg" # 上传附件名称(当前路径)
if send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name1,file_name2):
需要在发送函数定义中接收第二个附件的接收参数
def send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name1,file_name2):
需要在发送函数体中定义这个附件,添加设置属性,样子是一样的。只是把文件名字都换成第二个文件的就行
att2 = MIMEText(open(file_name2, 'rb').read(), 'base64', 'utf-8') # 添加附件
att2["Content-Type"] = 'application/octet-stream' # 设置类型
att2["Content-Disposition"] = 'attachment; filename="{0}"'.format(file_name2) # 设置邮件用现实的名称
message.attach(att2)
下面是比较完美的邮件。发送抄送附件以及html美化邮件内容
from jinja2 import PackageLoader, Environment, FileSystemLoader dic={ "10.0.0.11":{"host":"10.0.0.11","hostname":"mcw01","mem":"20%"}, "10.0.0.12":{"host":"10.0.0.12","hostname":"mcw02","mem":"60%"}, "10.0.0.13":{"host":"10.0.0.13","hostname":"mcw03","mem":"55%"} } path_dir = r'C:\mcw\testt\templates\\' #模板文件所在的绝对路径 loader = FileSystemLoader(searchpath=path_dir) env = Environment(loader=loader) template = env.get_template("jinja2研究.html") # 第一步将模板文件放到这里 buf = template.render(dic=dic,) #第二步将模板文件中用来渲染的数据传进去。用变量接收渲染后的html页面源码 # with open(os.path.join(path_dir, "jinja2xxx.html"), "w" ) as fp: #可以将buf模板渲染后的数据重新写入另一个文件 # fp.write(buf) #这里重新写入文件的时候,中文会出现乱码 print(buf) #1.导包 import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import logging #2.定义发送邮件函数 def send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name): message = MIMEMultipart() message['From'] = MAIL_USERNAME # 发件人 message['To'] = ";".join(accept_list) # 收件人,将列表转换为字符串 message["Cc"] = ";".join(Cc_list) # 抄送人,将列表转换为字符串 message['Subject'] = SUBJECT # 邮件主题 message.attach(MIMEText(text, 'html', 'utf-8')) # 格式化邮件内容,编码为utf-8.修改格式为html att1 = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') # 添加附件 att1["Content-Type"] = 'application/octet-stream' # 设置类型 att1["Content-Disposition"] = 'attachment; filename="{0}"'.format('test.xlsx') # 设置附件用现实的名称 message.attach(att1) try: mailServer = smtplib.SMTP(MAIL_SERVER, 25) # 25为端口号(邮件) # 登录邮箱 mailServer.login(MAIL_USERNAME, MAIL_PASSWORD) # 需要的是,邮箱的地址和授权密码 # 发送文件 mailServer.sendmail(MAIL_USERNAME, accept_list + Cc_list, message.as_string()) mailServer.close() # 关闭连接 return True except Exception as e: # logging.debug(e) print(e) return False #3.调用发送邮件函数 def main(): MAIL_SERVER = 'smtp.sina.com' # smtp服务器 MAIL_USERNAME = 'dxx@sina.com' # 发件人 MAIL_PASSWORD = '15xx' # 发送者授权码 accept_list = ['8xx@qq.com',] # 收件人 Cc_list = ['8xx@qq.com', '28x@qq.com'] # 抄送人 SUBJECT = "我是邮件主题" # 主题也是标题 text = buf # 内容 file_name = r"C:\mcw\testt\templates\youjian.html" # 上传附件名称(当前路径) if send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name): logging.debug("Send mail succed!") else: logging.debug("Send mail failed") if __name__ == '__main__': main()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body > <div style="background-color: blue;width: 500px;height: 200px"> <table border="1" cellspacing="0" style="height: 150px;width: 100%"> <thead> <tr style="background-color: gold;"> <th>主机ip</th> <th>主机名</th> <th>内存使用率</th> </tr> </thead> <tbody> {% for k,foo in dic.items() %} <tr style="background-color: gold;"> <td>{{ foo.host }}</td> <td>{{ foo.hostname }}</td> <td>{{ foo.mem }}</td> </tr> {% endfor %} </tbody> </table> </div> </body> </html>
邮件内容带图片,成功半步,可能是邮箱不支持把
1、将图片编码,转成字符串把编码后的b''去掉
import base64
img_file = open(r'C:\mcw\testt\templates\mcw.jpg', 'rb')
base64_data = str(base64.b64encode(img_file.read())).rstrip("'").lstrip("b'")
2、将编码后的字符串渲染到html页面中
html页面中调用:
<img src="data:image/png;base64,{{ base64_data }}" alt="image1" style="height: 200px;width: 100%">
python程序将字符串传进模板
buf = template.render(dic=dic,base64_data=base64_data) #第二步将模板文件中用来渲染的数据传进去。用变量接收渲染后的html页面源码
3、将html源码传给邮件的内容中,html格式
4、把源码保存下来自己访问效果:
图片是有的
把html数据发送给邮件的效果:
读不出来图片
import os from jinja2 import PackageLoader, Environment, FileSystemLoader dic={ "10.0.0.11":{"host":"10.0.0.11","hostname":"mcw01","mem":"20%"}, "10.0.0.12":{"host":"10.0.0.12","hostname":"mcw02","mem":"60%"}, "10.0.0.13":{"host":"10.0.0.13","hostname":"mcw03","mem":"55%"} } import base64 img_file = open(r'C:\mcw\testt\templates\mcw.jpg', 'rb') base64_data = str(base64.b64encode(img_file.read())).rstrip("'").lstrip("b'") path_dir = r'C:\mcw\testt\templates\\' #模板文件所在的绝对路径 loader = FileSystemLoader(searchpath=path_dir) env = Environment(loader=loader) template = env.get_template("jinja2研究.html") # 第一步将模板文件放到这里 buf = template.render(dic=dic,base64_data=base64_data) #第二步将模板文件中用来渲染的数据传进去。用变量接收渲染后的html页面源码 with open(os.path.join(path_dir, "jinja2xxx.html"), "w" ) as fp: #可以将buf模板渲染后的数据重新写入另一个文件 fp.write(buf) #这里重新写入文件的时候,中文会出现乱码 print(buf) # img_file = open(r'C:\mcw\testt\templates\mcw.jpg', 'rb') # base64_data = str(base64.b64encode(img_file.read())) # buf = buf % (base64_data) # #1.导包 import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import logging from email.mime.image import MIMEImage #2.定义发送邮件函数 def send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name): message = MIMEMultipart('related') # 邮件类型,如果要加图片等附件,就得是这个 message['From'] = MAIL_USERNAME # 发件人 message['To'] = ";".join(accept_list) # 收件人,将列表转换为字符串 message["Cc"] = ";".join(Cc_list) # 抄送人,将列表转换为字符串 message['Subject'] = SUBJECT # 邮件主题 # import base64 # img_file = open(r'C:\mcw\testt\templates\mcw.jpg', 'rb') # base64_data = str(base64.b64encode(img_file.read())) # text = text % (base64_data) # print(text) # return message.attach(MIMEText(text, 'html', 'utf-8')) # 格式化邮件内容,编码为utf-8.修改格式为html att1 = MIMEText(open(file_name, 'rb').read(), 'base64', 'utf-8') # 添加附件 att1["Content-Type"] = 'application/octet-stream' # 设置类型 att1["Content-Disposition"] = 'attachment; filename="{0}"'.format('test.xlsx') # 设置附件用现实的名称 message.attach(att1) # fp = open(r'C:\mcw\testt\templates\mcw.jpg', 'rb') # msgImage = MIMEImage(fp.read()) # fp.close() # msgImage.add_header('Content-ID', 'image1') # 这个id用于上面html获取图片 # message.attach(msgImage) try: mailServer = smtplib.SMTP(MAIL_SERVER, 25) # 25为端口号(邮件) # 登录邮箱 mailServer.login(MAIL_USERNAME, MAIL_PASSWORD) # 需要的是,邮箱的地址和授权密码 # 发送文件 mailServer.sendmail(MAIL_USERNAME, accept_list + Cc_list, message.as_string()) mailServer.close() # 关闭连接 return True except Exception as e: # logging.debug(e) print(e) return False #3.调用发送邮件函数 def main(): MAIL_SERVER = 'smtp.sina.com' # smtp服务器 MAIL_USERNAME = 'daxx@sina.com' # 发件人 MAIL_PASSWORD = '15xx' # 发送者授权码 accept_list = ['8xx@qq.com',] # 收件人 Cc_list = ['8xx@qq.com', '2xx@qq.com'] # 抄送人 SUBJECT = "我是邮件主题" # 主题也是标题 text = buf # 内容 file_name = r"C:\mcw\testt\templates\youjian.html" # 上传附件名称(当前路径) if send_mail(MAIL_SERVER, MAIL_USERNAME, MAIL_PASSWORD, accept_list, Cc_list, SUBJECT, text, file_name): logging.debug("Send mail succed!") else: logging.debug("Send mail failed") if __name__ == '__main__': main()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body > <div style=";width: 500px;height: 200px"> <table border="1" cellspacing="0" style="height: 150px;width: 100%"> <thead> <tr style=""> <th>主机ip</th> <th>主机名</th> <th>内存使用率</th> </tr> </thead> <tbody> {% for k,foo in dic.items() %} <tr style=""> <td>{{ foo.host }}</td> <td>{{ foo.hostname }}</td> <td>{{ foo.mem }}</td> </tr> {% endfor %} </tbody> </table> <img src="data:image/png;base64,{{ base64_data }}" alt="image1" style="height: 200px;width: 100%"> </div> </body> </html>
我手动把图片编码复制上去,是能显示的
貌似邮箱会把我们的字符串替换掉,导致无法访问图片,如下,真实访问是到的是这样的,我们加载进邮件消息对象之前是有图片编码的,那么问题可能是出在加载进图片对象时把这个编码字符串弄丢了,或者是邮箱服务器给我们替换掉了,显然跟html同为字符串,加载进消息对象时弄丢的可能性不大。
参考链接:https://vimsky.com/zh-tw/examples/detail/python-method-smtplib.SMTPSenderRefused.html