为什么每个邮件收到后都会有一个htm的附件_Python 发送邮件各种姿势
电子邮件是互联网应用最广的通讯服务,在工作中经常会有自动发邮件的需求,例如监控告警、注册通知、激活链接等。
而发送邮件是基于SMTP协议,接收邮件则是基于POP3或IMAP协议。
那POP3与IMAP协议又有什么区别呢?
最主要的区别是POP3在客户端邮箱中所做的操作不会反馈到邮箱服务器,比如删除一封邮件,邮箱服务器并不会删除。IMAP则会反馈到邮箱服务器,会做相应的操作。
Python对邮件服务完整的支持,分别提供相应的标准库:smtplib、poplib和imaplib。
顾名思义,其中smtplib库是用于发送邮件的,该库主要用smtplib.SMTP()类,它用于连接SMTP服务器和发送邮件。
这个类有几个常用的方法:
方法 |
描述 |
SMTP.set_debuglevel(level) |
设置输出debug调试信息,默认不输出 |
SMTP.docmd(cmd[, argstring]) |
发送一个命令到SMTP服务器 |
SMTP.connect([host[, port]]) |
连接到指定的SMTP服务器 |
SMTP.helo([hostname]) |
使用helo指令向SMTP服务器确认你的身份 |
SMTP.ehlo(hostname) |
使用ehlo指令像ESMTP(SMTP扩展)确认你的身份 |
SMTP.ehlo_or_helo_if_needed() |
如果在以前的会话连接中没有提供ehlo或者helo指令,这个方法会调用ehlo()或helo() |
SMTP.has_extn(name) |
判断指定名称是否在SMTP服务器上 |
SMTP.verify(address) |
判断邮件地址是否在SMTP服务器上 |
SMTP.starttls([keyfile[, certfile]]) |
使SMTP连接运行在TLS模式,所有的SMTP指令都会被加密 |
SMTP.login(user, password) |
登录SMTP服务器 |
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) |
发送邮件 from_addr:邮件发件人 to_addrs:邮件收件人 msg:发送消息 |
SMTP.quit() |
关闭SMTP会话 |
SMTP.close() |
关闭SMTP服务器连接 |
先看看官方示例:
>>> import smtplib>>> s=smtplib.SMTP("localhost")>>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]>>> msg = '''\ ... From: Me@my.org ... Subject: testin'... ... ... This is a test '''>>> s.sendmail("me@my.org",tolist,msg) { "three@three.org" : ( 550 ,"User unknown" ) }>>> s.quit()
接下来,给你分享 5 种最常用的发送邮件方式。
1、Python发送文本邮件
为方便测试,先在本机安装一个邮件服务,比如sendmail、postfix等。这里使用sendmail,如果你是CentOS系统直接安装启动即可:
# yum install sendmail# service sendmail start
按照官方示例在Python解释器执行:
>>> import smtplib>>> s = smtplib.SMTP("localhost")>>> tolist = ["xxx@qq.com", "xxx@163.com"]>>> msg = '''\... From: Me@my.org... Subject: test... This is a test '''>>> s.sendmail("me@my.org", tolist, msg){}
进入腾讯和网易收件人邮箱,就能看到刚发的测试邮件了,如果没有,请到垃圾邮箱看看。
可以看到,多个收件人可以放到一个列表中进行群发。msg对象里From表示发件人,Subject是邮件标题,换行后输入的是邮件内容。
使用自建邮箱服务器经常会出现被当做垃圾邮件、发件延迟,为解决这两个问题,一般使用知名邮件运营商。
例如使用163个人邮件作为发件人:
>>> import smtplib>>> s = smtplib.SMTP("smtp.163.com")>>> s.login("xxx@163.com", "xxx")(235, 'Authentication successful')>>> tolist = ["xxx@qq.com", "xxx@163.com"]>>> msg = '''\... From: xxx@163.com... Subject: test... This is a test '''>>> s.sendmail("xxx@163.com", tolist, msg)Traceback (most recent call last): File "", line 1, in File "/usr/lib64/python2.6/smtplib.py", line 725, in sendmailraise SMTPDataError(code, resp)smtplib.SMTPDataError: (554, 'DT:SPM 163 smtp10,DsCowAAXIdDIJAtYkZiTAA--.65425S2 1477125592,please see http://mail.163.com/help/help_spam_16.htm?ip=119.57.73.67&hostid=smtp10&time=1477125592')
访问给出的163网址,SMTP554错误是:”554 DT:SUM 信封发件人和信头发件人不匹配;”
大概已经明白啥意思,看上面再使用本地SMTP服务器时候,收件人位置是“undisclosed-recipients”,看这样163的SMTP服务器不给我们服务的原因就是这里收件人没指定。重新修改下msg对象,添加上收件人:
>>> msg = '''\... From: xxx@163.com... To: xxx@qq.com ,xxx@163.com... Subject: test...... This is a test '''>>> s.sendmail("xxx@163.com", tolist, msg){}
这样就可以正常发送邮件了。msg这个格式是SMTP规定的,一定要遵守。
2、发送邮件并抄送
#!/usr/bin/python# -*- coding: utf-8 -*-import smtplibdef sendMail(body): smtp_server = 'smtp.163.com' from_mail = 'xxx@163.com' mail_pass = 'xxx' to_mail = ['xxx@qq.com', 'xxx@163.com'] cc_mail = ['xxx@gmail.com'] from_name = 'monitor' subject = u'监控'.encode('gbk') # 以gbk编码发送,一般邮件客户端都能识别# msg = '''\# From: %s # To: %s# Subject: %s# %s''' %(from_name, from_mail, to_mail_str, subject, body) # 这种方式必须将邮件头信息靠左,也就是每行开头不能用空格,否则报SMTP 554
mail = ["From: %s " % (from_name, from_mail),"To: %s" % ','.join(to_mail), # 转成字符串,以逗号分隔元素"Subject: %s" % subject,"Cc: %s" % ','.join(cc_mail),"", body ] msg = '\n'.join(mail) # 这种方式先将头信息放到列表中,然后用join拼接,并以换行符分隔元素,结果就是和上面注释一样了try: s = smtplib.SMTP() s.connect(smtp_server, '25') s.login(from_mail, mail_pass) s.sendmail(from_mail, to_mail+cc_mail, msg) s.quit()except smtplib.SMTPException as e:print "Error: %s" %eif __name__ == "__main__": sendMail("This is a test!")
s.sendmail(from_mail,to_mail+cc_mail, msg) 在这里注意下,收件人和抄送人为什么放一起发送呢?其实无论是收件人还是抄送人,它们收到的邮件都是一样的,SMTP都是认为收件人这样一封一封的发出。所以实际上并没有抄送这个概念,只是在邮件头加了抄送人的信息罢了!
另外,如果不需要抄送人,直接把上面cc的信息去掉即可。
3、Python发送邮件带附件
由于SMTP.sendmail()方法不支持添加附件,所以可以使用email模块来满足需求。email模块是一个构造邮件和解析邮件的模块。先看下如何用email库构造一个简单的邮件:
message = Message()message['Subject'] = '邮件主题'message['From'] = from_mailmessage['To'] = to_mailmessage['Cc'] = cc_mailmessage.set_payload('邮件内容')
基本的格式就是这样的。
继续回到主题,发送邮件带附件:
#!/usr/bin/python# -*- coding: utf-8 -*-import smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email import encodersfrom email.mime.base import MIMEBasefrom email.utils import parseaddr, formataddr
# 格式化邮件地址def formatAddr(s): name, addr = parseaddr(s)return formataddr((Header(name, 'utf-8').encode(), addr))
def sendMail(body, attachment): smtp_server = 'smtp.163.com' from_mail = 'xxx@163.com' mail_pass = 'xxx' to_mail = ['xxx@qq.com', 'xxx@163.com']
# 构造一个MIMEMultipart对象代表邮件本身 msg = MIMEMultipart()# Header对中文进行转码 msg['From'] = formatAddr('管理员 ' % from_mail).encode() msg['To'] = ','.join(to_mail) msg['Subject'] = Header('监控', 'utf-8').encode()
# plain代表纯文本 msg.attach(MIMEText(body, 'plain', 'utf-8'))
# 二进制方式模式文件with open(attachment, 'rb') as f:# MIMEBase表示附件的对象 mime = MIMEBase('text', 'txt', filename=attachment)# filename是显示附件名字 mime.add_header('Content-Disposition', 'attachment', filename=attachment)# 获取附件内容 mime.set_payload(f.read()) encoders.encode_base64(mime)# 作为附件添加到邮件 msg.attach(mime)try: s = smtplib.SMTP() s.connect(smtp_server, "25") s.login(from_mail, mail_pass) s.sendmail(from_mail, to_mail, msg.as_string()) # as_string()把MIMEText对象变成str s.quit()except smtplib.SMTPException as e:print "Error: %s" % eif __name__ == "__main__": sendMail('附件是测试数据, 请查收!', 'test.txt')
4、Python发送HTML邮件
#!/usr/bin/python# -*- coding: utf-8 -*-import smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email.utils import parseaddr, formataddr# 格式化邮件地址def formatAddr(s): name, addr = parseaddr(s)return formataddr((Header(name, 'utf-8').encode(), addr))def sendMail(body): smtp_server = 'smtp.163.com' from_mail = 'baojingtongzhi@163.com' mail_pass = 'xxx' to_mail = ['xxx@qq.com', 'xxx@163.com']# 构造一个MIMEMultipart对象代表邮件本身 msg = MIMEMultipart()# Header对中文进行转码 msg['From'] = formatAddr('管理员 ' % from_mail).encode() msg['To'] = ','.join(to_mail) msg['Subject'] = Header('监控', 'utf-8').encode() msg.attach(MIMEText(body, 'html', 'utf-8'))try: s = smtplib.SMTP() s.connect(smtp_server, "25") s.login(from_mail, mail_pass) s.sendmail(from_mail, to_mail, msg.as_string()) # as_string()把MIMEText对象变成str s.quit()except smtplib.SMTPException as e:print "Error: %s" % eif __name__ == "__main__": body = """
测试邮件
测试邮件
This is a test
"""
This is a test
"""
sendMail(body)
5、Python发送图片邮件
#!/usr/bin/python# -*- coding: utf-8 -*-import smtplibfrom email.mime.text import MIMETextfrom email.mime.image import MIMEImagefrom email.mime.multipart import MIMEMultipartfrom email.header import Headerfrom email.utils import parseaddr, formataddr
# 格式化邮件地址def formatAddr(s): name, addr = parseaddr(s)return formataddr((Header(name, 'utf-8').encode(), addr))
def sendMail(body, image): smtp_server = 'smtp.163.com' from_mail = 'xxx@163.com' mail_pass = 'xxx' to_mail = ['xxx@qq.com', 'xxx@163.com']
# 构造一个MIMEMultipart对象代表邮件本身 msg = MIMEMultipart()# Header对中文进行转码 msg['From'] = formatAddr('管理员 ' % from_mail).encode() msg['To'] = ','.join(to_mail) msg['Subject'] = Header('监控', 'utf-8').encode() msg.attach(MIMEText(body, 'html', 'utf-8'))
# 二进制模式读取图片with open(image, 'rb') as f: msgImage = MIMEImage(f.read())
# 定义图片ID msgImage.add_header('Content-ID', '') msg.attach(msgImage)
try: s = smtplib.SMTP() s.connect(smtp_server, "25") s.login(from_mail, mail_pass) s.sendmail(from_mail, to_mail, msg.as_string()) # as_string()把MIMEText对象变成str s.quit()except smtplib.SMTPException as e:print "Error: %s" % eif __name__ == "__main__": body = """
测试图片
# 引用图片
"""
sendMail(body, 'test.png')
- END -
推荐阅读:
非常详细的 Ceph 介绍、原理、架构
服务器产生大量 TIME_WAIT 状态的排查过程
不管你是开发还是运维,微服务这些你得知道!
10 个Linux Awk文本处理经典案例
30个Linux Shell脚本经典案例(上)
30个Linux Shell脚本经典案例(中)
30个Linux Shell脚本经典案例(下)
基于Kubernetes的DevOps流水线实战
年轻时偷的懒,迟早是要还的。点亮
为什么每个邮件收到后都会有一个htm的附件_Python 发送邮件各种姿势相关推荐
- 为什么每个邮件收到后都会有一个htm的附件_Python3.x 发送各种形式的告警邮件内容...
在写脚本时,放到后台运行,想知道执行情况,会通过邮件.短信.微信等方式通知管理员,邮件目前用的最多的通知方式.在linux下,Shell脚本发送邮件告警是件很简单的事,有现成的邮件服务软件或者调用运营 ...
- C#实现.Net对邮件进行DKIM签名和验证,支持附件,发送邮件签名后直接投递到对方服务器(无需己方邮件服务器)
项目地址 https://github.com/xiangyuecn/DKIM-Smtp-csharp 主要支持 对邮件进行DKIM签名,支持带附件 对整个邮件内容(.eml文件)的DKIM签名进行验 ...
- 神奇的数学之回文数(不论开始是什么正整数,在经过有限次正序数和倒序数相加的步骤后,都会得到一个回文数)
神奇的数学之回文数 Description 回文数是一种数字.如:8008, 这个数字正读是8008,倒读也是8008,正读倒读一样,所以这个数字就是回文数. 任取一个正整数,如果不是回文数,将该数与 ...
- 操作系统:为什么IO操作不占用CPU却会导致进程阻塞?Web服务器每接收一个请求都会创建一个新的线程吗?Tomcat服务器工作原理?
为什么IO操作不占用CPU却会导致进程阻塞?Web服务器每接收一个请求都会创建一个新的线程吗?这两个问题在我学操作系统以前我都挺困惑的.现在我来尝试着解答一下. 1. 为什么IO操作不占用CPU却会导 ...
- TURBOMAIL反垃圾邮件清洁工,还你一个清爽的邮箱
"清明时节雨纷纷,路上行人欲断魂",又到了一年一季的梅雨季节,看到阴沉沉的天气.湿漉漉的地面.发霉的墙壁等等,总让人心情郁闷.昏昏欲睡.员工们每天呼吸着灰蒙蒙的空气上班,再看到垃圾 ...
- Java的HttpClient类以POST方式提交数据,目标端收到后中文乱码
h ttpClient HttpMethod NameValuePair setRequestBody 今天开发时,遇到利用Java中HttpClient类以POST方式提交数据,目标收到后中文 ...
- 远程控制slam小车及pid调试PC与树莓派ssh链接时出现间歇性联通段开网络故障acailable I Destination Host Unreachable_然后5s后切换了一个地图
远程控制slam小车 1. 把小车树莓派及pc端ubuntu通过无线路由器连接到统一局域网中 2.登入路由器查看是设备是否连接成功 http://192.168.1.1/ 路由器密码 树莓派: zxc ...
- 手机发出的邮件可以撤回吗?已发出的邮件撤回后对方能看到吗?
我是一个刚入职会销岗位的打工人,在面试时,我的直属领导跟我说我们公司有自己的企业邮箱.当时我在想不会还是跟我上一份工作单位一样吧,每天都需要背着电脑去出差,当时我心想好累啊!但还是决定入职了这家公司, ...
- 90后都会选择的购车模式“网上购车平台一成首付”
90后都会选择的购车模式"网上购车平台一成首付" 相知,相识,相恋. 这是我与男朋友的爱情故事,在即将走入婚姻的殿堂开启小家生活,可是选车却成了我们的头等大事, 工作时间不长,所以 ...
最新文章
- java数据类型指定长度_判断(2分) Java的各种数据类型占用固定长度,与具体的软硬件平台环境无关...
- OpenCV计算时刻calculate moments的实例(附完整代码)
- 腾讯企业邮箱报错 smtp.exmail.qq.comport 465, isSSL false
- 机房管理系列之杀毒服务器维护
- 【使用注意】文件内容突然消失
- 软件研发作为一项工程而言,纳闷!
- jquery-数字渐变
- centos php编译,深入讲解CentOS PHP安装编译
- pandas DataFrame数据转为list
- linux下c语言版线程池
- 【三维路径规划】基于matlab粒子群算法无人机三维路径规划【含Matlab源码 015期】
- java线程的生命周期(图解)
- 全球排名前500的网站都是做什么的
- windows server 2008共享文件夹
- bios卡+型号+hp服务器,HPE Gen9 server UEFI BIOS下升级BIOS 阵列卡 HBA卡固件的操作方法...
- js 数字转为罗马数字(互转换),I 、II 、 III 、IV、V
- 微服务+微信小程序实现社区服务
- Python|判断一个5位数是不是回文数
- Wi-Fi Direct协议详解
- “明德”网友关于《郭初阳课堂实录》一书的介绍
热门文章
- HDOJ-1181 字符串首尾相连问题[DFS()+strcmp()]
- Linux VIM,引导流程解析
- 我的空间为什么叫IT人?
- 【摩天好课推荐】2.4 Python代码常见的逻辑结构
- PE关于导入表(IAT)知识复习
- Linux常用命令大全(转载收藏)
- BZOJ2002 [HNOI2010] 弹飞绵羊
- 【推导】Codeforces Round #364 (Div. 2) D. As Fast As Possible
- Design Pattern: Observer Pattern
- 3D Button Suite