python学习(21)smtp发送邮件

本文介绍python发送邮件模块smtplib以及相关MIME模块。
smtplib用于生成邮件发送的代理,发送邮件前需要通过MIMEText构造邮件内容。

发送纯文本邮件

下面是个发送纯文本邮件的例子。

import smtplib
from email.mime.text import MIMEText
msg_from='XXXXX@163.com'                                 
passwd='XXXXX'                                  
msg_to='XXXXX@qq.com'                                  
                            
subject="python邮件测试"                                       
content="这是我使用python smtplib及email模块发送的邮件"

msg = MIMEText(content)
msg['Subject'] = subject
msg['From'] = msg_from
msg['To'] = msg_to
try:
    #s = smtplib.SMTP_SSL("smtp.163.com",465)
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, msg_to, msg.as_string())
    print ("发送成功")
except smtplib.SMTPException as e:
    print ("发送失败")
finally:
    s.quit()

MIMEText实例化一个邮件对象,内容为content,对于邮件标题Subject,发件人From,以及收件人To需要以字典形式指出,或者通过add_header(下文会给出)添加,否则对方看不到这些信息。想要通过smtp发送邮件,需要打开指定邮箱的smtp协议,以及设置smtp授权密码。我设置的是163邮箱的。


1.png
2.png

设置好密码后,将上述代码中的passwd改为你的密码,msg_from改为你的邮箱。smtplib可以通过SMTP_SSL发送,也可以采用普通形式直接初始化,对应的两个参数分别是授权的smtp服务器地址和端口号,因为我设置的是163的,所以使用smtp.163.com服务器地址,端口号和服务器地址读者可以自己去查。通过生成的smtp实例,一次调用login,sendemail就可以发送了。最后记得调用quit退出。发送一封纯文本邮件,看一下效果


3.png

我们发现发件人标题显示的只有邮箱地址,没有昵称,可以采用parseaddr和formataddr对发件人信息完善。

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr

msg_from='XXXXX@163.com'                                 
passwd='XXXXX'                                  
msg_to='XXXXX@qq.com'
receivers = ['XXXXX@qq.com']                                
                            
subject="python邮件测试"                                       
content="这是我使用python smtplib及email模块发送的邮件"

msg = MIMEText(content,'plain','utf-8')
msg['Subject'] = Header(subject,'utf-8').encode()
msg['From'] = _format_addr('恋恋风辰 <%s>' %msg_from)
msg['To'] = msg_to

try:
    #s = smtplib.SMTP_SSL("smtp.163.com",465)
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, receivers, msg.as_string())
    print ("发送成功")
except smtplib.SMTPException as e:
    print ("发送失败")
finally:
    s.quit()

这样可以看到发件人的昵称了。我设置的是恋恋风辰。Header函数的作用是防止中文乱码。
Header对字符串按照utf-8方式编码。MIMEText中参数plain表示纯文本,utf-8表示纯文本的编码方式。


4.png

发送html邮件

发送html邮件和之前发送纯文本类似,只需要将plain变为html,即可。

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
msg_from = 'XXXXXX@163.com'
passwd = 'XXXXX'
msg_to='XXXXXX@qq.com'
receivers = ['XXXXXX@qq.com']
subject = 'python邮件测试html'
content = '<html><body><h1>Hello</h1>' +\
    '<p>send by <a href="http://www.python.org">Python</a>...</p>'

msg = MIMEText(content, 'html', 'utf-8')
msg['Subject'] = Header(subject, 'utf-8').encode()
msg['From'] = _format_addr('恋恋风辰 <%s>' %msg_from)
msg['To'] = msg_to

try:
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, receivers, msg.as_string())
    print('发送成功')
except smtplib.SMTPException as e:
    print('发送失败')
finally:
    s.quit()

看看效果:


5.png

发送带附件的邮件

发送带附件的邮件,和之前不同,需要通过MIMEMultipart创建邮件实例,
然后将文本,附件等通过attach方法绑定到邮件实例上,然后一起发送。

import smtplib
import email
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart   
from email.utils import parseaddr, formataddr
from email.mime.base import MIMEBase


def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

msg_from = 'XXXXX@163.com'
passwd = 'XXXXX'
msg_to='XXXXXX@qq.com'
receivers = ['XXXX@qq.com']
subject = 'python邮件测试附件'
content = '<html><body><h1>Hello</h1>' +\
    '<p>send by <a href="http://www.python.org">Python</a>...</p>'

#附件邮件对象
msg = MIMEMultipart()
msg['From'] = _format_addr('恋恋风辰 <%s>' %msg_from)
msg['To'] = msg_to
msg['Subject'] = Header(subject, 'utf-8').encode()
#添加正文
text = MIMEText(content, 'html','utf-8')
msg.attach(text)
#添加附件就是创建一个MIMEBase对象,然后attach到msg上。
with open('./email.jpg','rb') as f:
    #设置附件名字
    mime = MIMEBase('image', 'jpg', filename='text.jpg')
    #加上头信息
    mime.add_header('Content-Disposition','attachment',filename='test.jpg')
    mime.add_header('Content-ID','<0>')
    mime.add_header('X-Attachment-Id','0')
    #读取内容放入附件
    mime.set_payload(f.read())
    #用Base64编码
    email.encoders.encode_base64(mime)
    #添加到MIMEMultipart中
    msg.attach(mime)

try:
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, receivers, msg.as_string())
    print('发送成功')
except smtplib.SMTPException as e:
    print('发送失败')
finally:
    s.quit()

MIMEMultipart创建邮件实例msg,将收件人,发件人,主题设置到msg上。然后通过MIMEText创建html文本内容,调用msg.attach方法将文本内容绑定到邮件上。同样的道理,打开一个图片,通过MIMEBase创建一个附件实例,设置文件名,
文件类型,绑定的id等等,最后通过set_payload加载到附件,然后msg.attach绑定到邮件实例上。后面的发送流程和之前
一样。
看看效果:


6.png

发送带图片的html邮件

想要在html中添加图片,并且在邮件正文中显示,只需要在html文本中引用
图片id即可。

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart   
from email.utils import parseaddr, formataddr
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage


def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

msg_from = 'XXXXXXXXXXXX@163.com'
passwd = 'XXXXX'
msg_to='XXXXXXXXX@qq.com'
receivers = ['XXXXXXXXXX@qq.com']
subject = 'python邮件测试附件'
content = '<b>Some <i>HTML</i> text</b> and an image.<br><img src="cid:image1"><br>good!'

#附件邮件对象
msg = MIMEMultipart()
msg['From'] = _format_addr('恋恋风辰 <%s>' %msg_from)
msg['To'] = msg_to
msg['Subject'] = Header(subject, 'utf-8').encode()
#添加正文
text = MIMEText(content, 'html','utf-8')
msg.attach(text)

#添加附件就是创建一个MIMEBase对象,然后attach到msg上。
with open('./email.jpg','rb') as f:
    #设置附件名字
    mime = MIMEImage(f.read())
    #加上头信息
    mime.add_header('Content-Disposition','attachment',filename='test.jpg')
    mime.add_header('Content-ID','`<image1>`')
   
    #添加到MIMEMultipart中
    msg.attach(mime)

try:
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, receivers, msg.as_string())
    print('发送成功')
except smtplib.SMTPException as e:
    print('发送失败')
finally:
    s.quit()

mime.add_header('Content-ID','<image1>') 设置图片id为image1,
在html中引用image1就可以在邮件中文中显示图片了。
通过<img src="cid:image1">方式进行引用。

Messge类的继承和派生关系

Message
+- MIMEBase
  +- MIMEMultipart
  +- MIMENonMultipart
     +- MIMEMessage
     +- MIMEText
     +- MIMEImage

MIMEBase继承于Message,MIMEMultipart继承于MIMEBase。

用MIMEText发送多种附件

import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.utils import parseaddr, formataddr
import os

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

msg_from = 'XXXXXXXXX@163.com'
passwd = 'XXXXXXXXXXX'
msg_to='XXXXXXXXX@qq.com'
receivers = ['XXXXXXXXXXX@qq.com']
subject = 'python邮件测试附件'
content = '多种附件'

#附件邮件对象
msg = MIMEMultipart()
msg['From'] = _format_addr('恋恋风辰 <%s>' %msg_from)
msg['To'] = msg_to
msg['Subject'] = Header(subject, 'utf-8').encode()
#添加正文
text = MIMEText(content, 'html','utf-8')
msg.attach(text)

os.chdir('./res')    
dir = os.getcwd()

for fn in os.listdir(dir):
    print(fn)
    with open(fn,'rb') as f:
        mime = MIMEText(f.read(), 'base64', 'utf-8')
        mime.add_header('Content-Disposition','attachment',filename = fn)
        mime.add_header('Content-Type', 'application/octet-stream')
        msg.attach(mime)

try:
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, receivers, msg.as_string())
    print('发送成功')
except smtplib.SMTPException as e:
    print('发送失败')
finally:
    s.quit()

大体原理和之前一样,通过MIMEText可以实现多种附件的发送。
注意格式改为base64,编码用utf-8,可以实现多种附件发送。
效果如下:


7.png

通过MIMEApplication发送多种附件

同样可以通过MIMEApplication发送多种附件。

import smtplib
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.utils import parseaddr, formataddr
import os

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

msg_from = 'xxxxxxxxx@163.com'
passwd = 'xxxxxxxxxx'
msg_to='xxxxxxxxxxx@qq.com'
receivers = ['xxxxxxxxx@qq.com']
subject = 'python邮件测试附件'
content = '多种附件'

#附件邮件对象
msg = MIMEMultipart()
msg['From'] = _format_addr('恋恋风辰 <%s>' %msg_from)
msg['To'] = msg_to
msg['Subject'] = Header(subject, 'utf-8').encode()
#添加正文
text = MIMEText(content, 'html','utf-8')
msg.attach(text)

os.chdir('./res')    
dir = os.getcwd()

for fn in os.listdir(dir):
    print(fn)
    with open(fn,'rb') as f:
        mime = MIMEApplication(f.read())
        mime.add_header('Content-Disposition','attachment',filename = fn)
        mime.add_header('Content-Type', 'application/octet-stream')
        msg.attach(mime)

try:
    s = smtplib.SMTP("smtp.163.com",25)
    s.login(msg_from, passwd)
    s.sendmail(msg_from, receivers, msg.as_string())
    print('发送成功')
except smtplib.SMTPException as e:
    print('发送失败')
finally:
    s.quit()

效果和之前的一样,这就是python中利用smtplib和MIME构造邮件发送的案例。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容