关于Python基于SMTP协议发送邮件

来源:互联网 发布:域名转让 编辑:程序博客网 时间:2024/05/17 01:01

#Python基于smtp协议发送邮件

首先介绍下电子邮件的基本流程:

生气发件人 -> MUA -> MTA -> MTA -> 若干个MTA -> MDA <- MUA <- 收件人

生气MUA:Mail User Agent 邮件用户代理

生气MTA:Mail Transfer Agent 邮件传输代理

生气MDA:Mail Delivery Agent 邮件投递代理

发邮件时,MUA和MTA使用的协议就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一个MTA也是用SMTP协议

收邮件时,MUA和MDA使用的协议有两种:

POP:Post Office Protocol,目前版本是3,俗称POP3;

IMAP:Internet Message Access Protocol,目前版本是4,优点是不但能取邮件,还可以直接操作MDA上存储的邮件,比如从收件

箱移到垃圾箱,等等。

今天主要介绍的是基于SMTP的邮件发送:

SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。

Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。  
生气简单的发一个邮件:
from email.mime.text import MIMEText

import smtplib

msg = MIMEText('you are buautiful','plain','utf-8')

#第一个参数是邮件正文,第二个传plain表示纯文本,第三个utf-8保证了多语言的兼容性

from_addr = input('From:') #输入发件人地址  

password = input('password:')           #输入客户端授权密码

to_addr = input('To:')                #输入收件人地址

smtp_server = input('Smtp_server:')

#输入收件人邮箱的SMTP服务器 像网易163邮箱的就是smtp.163.com,可以查到的。注意不要写成stmp!!!!

msg['From'] = from_addr             #显示邮件的发信人

msg['To'] = to_addr                      #显示邮件的收信人

msg['Subject'] = 'love and peace'              #显示邮件的标题

server = smtplib.SMTP(smtp_server,25)            #注意这里SMTP协议默认端口25

#SMTP的构造函数,功能:与smtp服务器建立连接,在连接成功后,就可以向服务器发送相关请求,如登陆,校验,发送,退出等

server.set_debuglevel(1)                #打印出和SMTP服务器交互的所有信息,当然你可以选择去掉这句

server.login(from_addr,password)                 #登录SMTP服务器

server.sendmail(from_addr,[to_addr],msg.as_string())  

#发邮件,第二个参数是list,因为可以同时发给几个人嘛,至于as_string()是把MIMEText对象变成str。

server.quit()  #断开与SMTP服务器的连接


不出意外的话发送是能成功的,但邮件可能被邮箱放入垃圾箱了。。。。。。。。。。。

结果应该是这样:


但同时你也会发现,收件人和发件人显示的都是你邮箱默认的名字,但是你想自己起个名字怎么办呢

很简单你将上面那两句换成这两句就可以了

msg['From'] = 'sb <%s>' %from_addr

msg['To'] = 'gua pi <%s>' %to_addr

结果如下图:



但是你自己想起的名字是中文的,那么再简单的将上面两句换掉就不行了,

如果包含中文,需要通过Header对象进行编码。

from email.utils import parseaddr,formataddr

from email.header import Header

def A(s):        #创建一个函数A,用以得到Header处理后的地址

     a,b = parseaddr(s)   #parseaddr函数用于解析字符串中的email地址

     return formataddr((Header(a,'utf-8').encode(),b))

msg['From'] = A('傻逼 <%s>' %from_addr)

msg['To'] = A('瓜皮 <%s>' %to_addr)

msg['Subject'] = Header('爱与和平','utf-8').encode()


注意:

生气parseaddr()不是内置函数,见于email.utils, 用来解析字符串中的email地址

例如:注意邮箱必须用<>括起来才能解析

>>> A = 'helloworld<123144@qq.com>'

>>> from  email.utils import parseaddr,formataddr

>>> m,n = parseaddr(A)

>>> m

'helloworld'

>>> n

'123144@qq.com'

生气formataddr()则和parseaddr()相反:不过要注意的是传入的是一个tuple

>>> m

'helloworld'

>>> n

'123144@qq.com'

>>> formataddr((m,n))

'helloworld <123144@qq.com>'



而且你还想发送一张图片(作为附件)过去,怎么做呢??

带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,可以构造一个MIMEMultipart对象代表邮件本身,然后往

里面加上一个MIMEText作为邮件正文,再继续往里面加上表示附件的MIMEBase对象即可:

from email.mime.text import MIMEText

import smtplib

from email.mime.base import MIMEBase

from email import encoders

from email.mime.multipart import MIMEMultipart

from email.utils import parseaddr,formataddr

from email.header import Header

msg = MIMEMultipart()         #邮件对象

msg.attach(MIMEText('you are buautiful','plain','utf-8'))       #邮件正文是MIMEText,添加进去

with open(r'C:\Users\14547\Desktop\picture\me.jpg','rb') as f:

#添加附件就是添加一个MIMEBase,从本地读取一个图片

    mime = MIMEBase('image','png',filename = 'you.png')#设置附件的MIME和文件名,类型是png类型

    mime.add_header('Content-Disposition','attachment',filename = 'you.png')  #这里加上必要的头信息

    mime.add_header('Content-ID','0')

    mime.add_header('X-Attachment-Id','0')

    mime.set_payload(f.read())    #把附件的内容读进来

    encoders.encode_base64(mime)   #用Base64编码

    msg.attach(mime)    #添加到MIMEMultipart

def A(s):

    a,b = parseaddr(s)

    return formataddr((Header(a,'utf-8').encode(),b))

from_addr = input('From:')

password = input('password:')

to_addr = input('To:')  

smtp_server = input('Smtp_server:')

msg['From'] = A('傻逼 <%s>' %from_addr)

msg['To'] = A('瓜皮 <%s>' %to_addr)

msg['Subject'] = Header('爱与和平','utf-8').encode()

server = smtplib.SMTP(smtp_server,25)

server.set_debuglevel(1)

server.login(from_addr,password)

server.sendmail(from_addr,[to_addr],msg.as_string())

server.quit()


然后输出如下:可以看到名字是中文的然后内容也成功包含了附件。


2017.10.27.23:23 写的有点累,一些没有说明白的明天再说。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。