为什么每个邮件收到后都会有一个htm的附件_Python 发送邮件各种姿势
電子郵件是互聯(lián)網(wǎng)應(yīng)用最廣的通訊服務(wù),在工作中經(jīng)常會(huì)有自動(dòng)發(fā)郵件的需求,例如監(jiān)控告警、注冊(cè)通知、激活鏈接等。
而發(fā)送郵件是基于SMTP協(xié)議,接收郵件則是基于POP3或IMAP協(xié)議。
那POP3與IMAP協(xié)議又有什么區(qū)別呢?
最主要的區(qū)別是POP3在客戶端郵箱中所做的操作不會(huì)反饋到郵箱服務(wù)器,比如刪除一封郵件,郵箱服務(wù)器并不會(huì)刪除。IMAP則會(huì)反饋到郵箱服務(wù)器,會(huì)做相應(yīng)的操作。
Python對(duì)郵件服務(wù)完整的支持,分別提供相應(yīng)的標(biāo)準(zhǔn)庫:smtplib、poplib和imaplib。
顧名思義,其中smtplib庫是用于發(fā)送郵件的,該庫主要用smtplib.SMTP()類,它用于連接SMTP服務(wù)器和發(fā)送郵件。
這個(gè)類有幾個(gè)常用的方法:
方法 | 描述 |
SMTP.set_debuglevel(level) | 設(shè)置輸出debug調(diào)試信息,默認(rèn)不輸出 |
SMTP.docmd(cmd[, argstring]) | 發(fā)送一個(gè)命令到SMTP服務(wù)器 |
SMTP.connect([host[, port]]) | 連接到指定的SMTP服務(wù)器 |
SMTP.helo([hostname]) | 使用helo指令向SMTP服務(wù)器確認(rèn)你的身份 |
SMTP.ehlo(hostname) | 使用ehlo指令像ESMTP(SMTP擴(kuò)展)確認(rèn)你的身份 |
SMTP.ehlo_or_helo_if_needed() | 如果在以前的會(huì)話連接中沒有提供ehlo或者h(yuǎn)elo指令,這個(gè)方法會(huì)調(diào)用ehlo()或helo() |
SMTP.has_extn(name) | 判斷指定名稱是否在SMTP服務(wù)器上 |
SMTP.verify(address) | 判斷郵件地址是否在SMTP服務(wù)器上 |
SMTP.starttls([keyfile[, certfile]]) | 使SMTP連接運(yùn)行在TLS模式,所有的SMTP指令都會(huì)被加密 |
SMTP.login(user, password) | 登錄SMTP服務(wù)器 |
SMTP.sendmail(from_addr, to_addrs, msg, ?mail_options=[], rcpt_options=[]) | 發(fā)送郵件 from_addr:郵件發(fā)件人 to_addrs:郵件收件人 msg:發(fā)送消息 |
SMTP.quit() | 關(guān)閉SMTP會(huì)話 |
SMTP.close() | 關(guān)閉SMTP服務(wù)器連接 |
先看看官方示例:
>>> 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 種最常用的發(fā)送郵件方式。
1、Python發(fā)送文本郵件
為方便測(cè)試,先在本機(jī)安裝一個(gè)郵件服務(wù),比如sendmail、postfix等。這里使用sendmail,如果你是CentOS系統(tǒng)直接安裝啟動(dòng)即可:
# yum install sendmail# service sendmail start
按照官方示例在Python解釋器執(zhí)行:
>>> 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){}
進(jìn)入騰訊和網(wǎng)易收件人郵箱,就能看到剛發(fā)的測(cè)試郵件了,如果沒有,請(qǐng)到垃圾郵箱看看。
可以看到,多個(gè)收件人可以放到一個(gè)列表中進(jìn)行群發(fā)。msg對(duì)象里From表示發(fā)件人,Subject是郵件標(biāo)題,換行后輸入的是郵件內(nèi)容。
使用自建郵箱服務(wù)器經(jīng)常會(huì)出現(xiàn)被當(dāng)做垃圾郵件、發(fā)件延遲,為解決這兩個(gè)問題,一般使用知名郵件運(yùn)營(yíng)商。
例如使用163個(gè)人郵件作為發(fā)件人:
>>> 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網(wǎng)址,SMTP554錯(cuò)誤是:”554 DT:SUM 信封發(fā)件人和信頭發(fā)件人不匹配;”
大概已經(jīng)明白啥意思,看上面再使用本地SMTP服務(wù)器時(shí)候,收件人位置是“undisclosed-recipients”,看這樣163的SMTP服務(wù)器不給我們服務(wù)的原因就是這里收件人沒指定。重新修改下msg對(duì)象,添加上收件人:
>>> 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)
{}
這樣就可以正常發(fā)送郵件了。msg這個(gè)格式是SMTP規(guī)定的,一定要遵守。
2、發(fā)送郵件并抄送
#!/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'監(jiān)控'.encode('gbk') # 以gbk編碼發(fā)送,一般郵件客戶端都能識(shí)別# msg = '''\# From: %s # To: %s# Subject: %s# %s''' %(from_name, from_mail, to_mail_str, subject, body) # 這種方式必須將郵件頭信息靠左,也就是每行開頭不能用空格,否則報(bào)SMTP 554
mail = ["From: %s " % (from_name, from_mail),"To: %s" % ','.join(to_mail), # 轉(zhuǎn)成字符串,以逗號(hào)分隔元素"Subject: %s" % subject,"Cc: %s" % ','.join(cc_mail),"",
body
]
msg = '\n'.join(mail) # 這種方式先將頭信息放到列表中,然后用join拼接,并以換行符分隔元素,結(jié)果就是和上面注釋一樣了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) 在這里注意下,收件人和抄送人為什么放一起發(fā)送呢?其實(shí)無論是收件人還是抄送人,它們收到的郵件都是一樣的,SMTP都是認(rèn)為收件人這樣一封一封的發(fā)出。所以實(shí)際上并沒有抄送這個(gè)概念,只是在郵件頭加了抄送人的信息罷了!
另外,如果不需要抄送人,直接把上面cc的信息去掉即可。
3、Python發(fā)送郵件帶附件
由于SMTP.sendmail()方法不支持添加附件,所以可以使用email模塊來滿足需求。email模塊是一個(gè)構(gòu)造郵件和解析郵件的模塊。先看下如何用email庫構(gòu)造一個(gè)簡(jiǎn)單的郵件:
message = Message()message['Subject'] = '郵件主題'
message['From'] = from_mail
message['To'] = to_mail
message['Cc'] = cc_mail
message.set_payload('郵件內(nèi)容')
基本的格式就是這樣的。
繼續(xù)回到主題,發(fā)送郵件帶附件:
#!/usr/bin/python# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email import encoders
from email.mime.base import MIMEBase
from 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']
# 構(gòu)造一個(gè)MIMEMultipart對(duì)象代表郵件本身
msg = MIMEMultipart()
# Header對(duì)中文進(jìn)行轉(zhuǎn)碼
msg['From'] = formatAddr('管理員 ' % from_mail).encode()
msg['To'] = ','.join(to_mail)
msg['Subject'] = Header('監(jiān)控', 'utf-8').encode()
# plain代表純文本
msg.attach(MIMEText(body, 'plain', 'utf-8'))
# 二進(jìn)制方式模式文件
with open(attachment, 'rb') as f:
# MIMEBase表示附件的對(duì)象
mime = MIMEBase('text', 'txt', filename=attachment)
# filename是顯示附件名字
mime.add_header('Content-Disposition', 'attachment', filename=attachment)
# 獲取附件內(nèi)容
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對(duì)象變成str
s.quit()
except smtplib.SMTPException as e:
print "Error: %s" % e
if __name__ == "__main__":
sendMail('附件是測(cè)試數(shù)據(jù), 請(qǐng)查收!', 'test.txt')
4、Python發(fā)送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']# 構(gòu)造一個(gè)MIMEMultipart對(duì)象代表郵件本身
msg = MIMEMultipart()# Header對(duì)中文進(jìn)行轉(zhuǎn)碼
msg['From'] = formatAddr('管理員 ' % from_mail).encode()
msg['To'] = ','.join(to_mail)
msg['Subject'] = Header('監(jiān)控', '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對(duì)象變成str
s.quit()except smtplib.SMTPException as e:print "Error: %s" % eif __name__ == "__main__":
body = """
測(cè)試郵件
This is a test
"""
sendMail(body)
5、Python發(fā)送圖片郵件
#!/usr/bin/python# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.header import Header
from 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']
# 構(gòu)造一個(gè)MIMEMultipart對(duì)象代表郵件本身
msg = MIMEMultipart()# Header對(duì)中文進(jìn)行轉(zhuǎn)碼
msg['From'] = formatAddr('管理員 ' % from_mail).encode()
msg['To'] = ','.join(to_mail)
msg['Subject'] = Header('監(jiān)控', 'utf-8').encode()
msg.attach(MIMEText(body, 'html', 'utf-8'))
# 二進(jìn)制模式讀取圖片
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對(duì)象變成str
s.quit()
except smtplib.SMTPException as e:
print "Error: %s" % e
if __name__ == "__main__":
body = """
測(cè)試圖片
# 引用圖片"""
sendMail(body, 'test.png')
-?END?-
推薦閱讀:
非常詳細(xì)的 Ceph 介紹、原理、架構(gòu)
服務(wù)器產(chǎn)生大量 TIME_WAIT 狀態(tài)的排查過程
不管你是開發(fā)還是運(yùn)維,微服務(wù)這些你得知道!
10 個(gè)Linux Awk文本處理經(jīng)典案例
30個(gè)Linux Shell腳本經(jīng)典案例(上)
30個(gè)Linux Shell腳本經(jīng)典案例(中)
30個(gè)Linux Shell腳本經(jīng)典案例(下)
基于Kubernetes的DevOps流水線實(shí)戰(zhàn)?
年輕時(shí)偷的懶,遲早是要還的。點(diǎn)亮
總結(jié)
以上是生活随笔為你收集整理的为什么每个邮件收到后都会有一个htm的附件_Python 发送邮件各种姿势的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 主键id 请求参数用什么类型_中小型项目
- 下一篇: invoke 数组_对于反射中的invo